diff --git a/.gitee/ISSUE_TEMPLATE.md b/.gitee/ISSUE_TEMPLATE.md
index cdae693d35..a0b60ba750 100644
--- a/.gitee/ISSUE_TEMPLATE.md
+++ b/.gitee/ISSUE_TEMPLATE.md
@@ -1,4 +1,4 @@
-强烈建议大家到 `github` 相关页面提交问题，方便统一查询管理，具体页面地址：https://github.com/Wechat-Group/WxJava/issues
+强烈建议大家到 `github` 相关页面提交问题，方便统一查询管理，具体页面地址：https://github.com/binarywang/WxJava/issues
 
 当然如果必须在这里提问，请务必按以下格式填写，谢谢配合~
 
diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
new file mode 100644
index 0000000000..cec0d76c6b
--- /dev/null
+++ b/.github/copilot-instructions.md
@@ -0,0 +1,198 @@
+# WxJava - WeChat Java SDK Development Instructions
+
+WxJava is a comprehensive WeChat Java SDK supporting multiple WeChat platforms including Official Accounts (公众号), Mini Programs (小程序), WeChat Pay (微信支付), Enterprise WeChat (企业微信), Open Platform (开放平台), and Channel/Video (视频号). This is a Maven multi-module project with Spring Boot and Solon framework integrations.
+
+**ALWAYS reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the information here.**
+
+## Working Effectively
+
+### Prerequisites and Environment Setup
+- **Java Requirements**: JDK 8+ required (project uses Java 8 as minimum target)
+- **Maven**: Maven 3.6+ recommended (Maven 3.9.11 validated)
+- **IDE**: IntelliJ IDEA recommended (project optimized for IDEA)
+
+### Bootstrap, Build, and Validate
+Execute these commands in sequence after cloning:
+
+```bash
+# 1. Basic compilation (NEVER CANCEL - takes 4-5 minutes)
+mvn clean compile -DskipTests=true --no-transfer-progress
+# Timeout: Set 8+ minutes. Actual time: ~4 minutes
+
+# 2. Full package build (NEVER CANCEL - takes 2-3 minutes)  
+mvn clean package -DskipTests=true --no-transfer-progress
+# Timeout: Set 5+ minutes. Actual time: ~2 minutes
+
+# 3. Code quality validation (NEVER CANCEL - takes 45-60 seconds)
+mvn checkstyle:check --no-transfer-progress
+# Timeout: Set 3+ minutes. Actual time: ~50 seconds
+```
+
+**CRITICAL TIMING NOTES:**
+- **NEVER CANCEL** any Maven build command
+- Compilation phase takes longest (~4 minutes) due to 34 modules
+- Full builds are faster on subsequent runs due to incremental compilation
+- Always use `--no-transfer-progress` to reduce log noise
+
+### Testing Structure
+- **Test Framework**: TestNG (not JUnit)
+- **Test Files**: 298 test files across all modules  
+- **Default Behavior**: Tests are DISABLED by default in pom.xml (`<skip>true</skip>`)
+- **Test Configuration**: Tests require external WeChat API credentials via test-config.xml files
+- **DO NOT** attempt to run tests without proper WeChat API credentials as they will fail
+
+## Project Structure and Navigation
+
+### Core SDK Modules (Main Development Areas)
+- `weixin-java-common/` - Common utilities and base classes (most important)
+- `weixin-java-mp/` - WeChat Official Account SDK (公众号)
+- `weixin-java-pay/` - WeChat Pay SDK (微信支付) 
+- `weixin-java-miniapp/` - Mini Program SDK (小程序)
+- `weixin-java-cp/` - Enterprise WeChat SDK (企业微信)
+- `weixin-java-open/` - Open Platform SDK (开放平台)
+- `weixin-java-channel/` - Channel/Video SDK (视频号)
+- `weixin-java-qidian/` - Qidian SDK (企点)
+
+### Framework Integration Modules
+- `spring-boot-starters/` - Spring Boot auto-configuration starters
+- `solon-plugins/` - Solon framework plugins
+- `weixin-graal/` - GraalVM native image support
+
+### Configuration and Quality
+- `quality-checks/google_checks.xml` - Checkstyle configuration
+- `.editorconfig` - Code formatting rules (2 spaces = 1 tab)
+- `pom.xml` - Root Maven configuration
+
+## Development Workflow
+
+### Making Code Changes
+1. **Always build first** to establish clean baseline:
+   ```bash
+   mvn clean compile --no-transfer-progress
+   ```
+
+2. **Follow code style** (enforced by checkstyle):
+   - Use 2 spaces for indentation (not tabs)
+   - Follow Google Java Style Guide
+   - Install EditorConfig plugin in your IDE
+
+3. **Validate changes incrementally**:
+   ```bash
+   # After each change:
+   mvn compile --no-transfer-progress
+   mvn checkstyle:check --no-transfer-progress  
+   ```
+
+### Before Submitting Changes
+**ALWAYS run these validation steps in sequence:**
+
+1. **Code Style Validation**:
+   ```bash
+   mvn checkstyle:check --no-transfer-progress
+   # Must pass - takes ~50 seconds
+   ```
+
+2. **Full Clean Build**:
+   ```bash
+   mvn clean package -DskipTests=true --no-transfer-progress  
+   # Must succeed - takes ~2 minutes
+   ```
+
+3. **Documentation**: Update javadoc for public methods and classes
+4. **Contribution Guidelines**: Follow `CONTRIBUTING.md` - PRs must target `develop` branch
+
+## Module Dependencies and Build Order
+
+### Core Module Dependencies (Build Order)
+1. `weixin-graal` (GraalVM support)
+2. `weixin-java-common` (foundation for all other modules)
+3. Core SDK modules (mp, pay, miniapp, cp, open, channel, qidian)
+4. Framework integrations (spring-boot-starters, solon-plugins)
+
+### Key Relationship Patterns
+- All SDK modules depend on `weixin-java-common`
+- Spring Boot starters depend on corresponding SDK modules
+- Solon plugins follow same pattern as Spring Boot starters
+- Each module has both single and multi-account configurations
+
+## Common Tasks and Commands
+
+### Validate Specific Module
+```bash
+# Build single module (replace 'weixin-java-mp' with target module):
+cd weixin-java-mp
+mvn clean compile --no-transfer-progress
+```
+
+### Check Dependencies
+```bash
+# Analyze dependencies:
+mvn dependency:tree --no-transfer-progress
+
+# Check for dependency updates:  
+./others/check-dependency-updates.sh
+```
+
+### Release and Publishing
+```bash
+# Version check:
+mvn versions:display-property-updates --no-transfer-progress
+
+# Deploy (requires credentials):
+mvn clean deploy -P release --no-transfer-progress
+```
+
+## Important Files and Locations
+
+### Configuration Files
+- `pom.xml` - Root Maven configuration with dependency management
+- `quality-checks/google_checks.xml` - Checkstyle rules
+- `.editorconfig` - IDE formatting configuration
+- `.github/workflows/maven-publish.yml` - CI/CD pipeline
+
+### Documentation
+- `README.md` - Project overview and usage (Chinese)
+- `CONTRIBUTING.md` - Development contribution guidelines  
+- `demo.md` - Links to demo projects and examples
+- Each module has dedicated documentation and examples
+
+### Test Resources
+- `*/src/test/resources/test-config.sample.xml` - Template for test configuration
+- Tests require real WeChat API credentials to run
+
+## SDK Usage Patterns
+
+### Maven Dependency Usage
+```xml
+<dependency>
+  <groupId>com.github.binarywang</groupId>
+  <artifactId>weixin-java-mp</artifactId>  <!-- or other modules -->
+  <version>4.7.0</version>
+</dependency>
+```
+
+### Common Development Areas
+- **API Client Implementation**: Located in `*/service/impl/` directories
+- **Model Classes**: Located in `*/bean/` directories  
+- **Configuration**: Located in `*/config/` directories
+- **Utilities**: Located in `*/util/` directories in weixin-java-common
+
+## Troubleshooting
+
+### Build Issues
+- **OutOfMemoryError**: Increase Maven memory: `export MAVEN_OPTS="-Xmx2g"`
+- **Compilation Failures**: Usually dependency issues - run `mvn clean` first
+- **Checkstyle Failures**: Check `.editorconfig` settings in IDE
+
+### Common Gotchas
+- **Tests Always Skip**: This is normal - tests require WeChat API credentials
+- **Multi-Module Changes**: Always build from root, not individual modules
+- **Branch Target**: PRs must target `develop` branch, not `master`/`release`
+
+## Performance Notes
+- **First Build**: Takes 4-5 minutes due to dependency downloads
+- **Incremental Builds**: Much faster (~30-60 seconds)
+- **Checkstyle**: Runs quickly (~50 seconds) and should be run frequently
+- **IDE Performance**: Project uses Lombok - ensure annotation processing is enabled
+
+Remember: This is a SDK library project, not a runnable application. Changes should focus on API functionality, not application behavior.
\ No newline at end of file
diff --git a/.github/workflows b/.github/workflows
deleted file mode 100644
index e420c7d44d..0000000000
--- a/.github/workflows
+++ /dev/null
@@ -1,4 +0,0 @@
-- name: Upload coverage reports to Codecov
-  uses: codecov/codecov-action@v3
-  env:
-    CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
diff --git a/.github/workflows/maven-publish.yml b/.github/workflows/maven-publish.yml
new file mode 100644
index 0000000000..de68370ae1
--- /dev/null
+++ b/.github/workflows/maven-publish.yml
@@ -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 }}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c703964824..0b16b4779e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -28,7 +28,7 @@ $ git push
 * 定期使用项目仓库内容更新自己仓库内容。
 
 ```bash
-$ git remote add upstream https://github.com/Wechat-Group/WxJava
+$ git remote add upstream https://github.com/binarywang/WxJava
 $ git fetch upstream
 $ git checkout develop
 $ git rebase upstream/develop
diff --git a/NEW_TRANSFER_API_SUPPORT.md b/NEW_TRANSFER_API_SUPPORT.md
new file mode 100644
index 0000000000..c7e9eaf490
--- /dev/null
+++ b/NEW_TRANSFER_API_SUPPORT.md
@@ -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进行商户转账操作！
\ No newline at end of file
diff --git a/NEW_TRANSFER_API_USAGE.md b/NEW_TRANSFER_API_USAGE.md
new file mode 100644
index 0000000000..9d1ac8254a
--- /dev/null
+++ b/NEW_TRANSFER_API_USAGE.md
@@ -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功能。
\ No newline at end of file
diff --git a/README.md b/README.md
index 3654f2cd80..e8c981bbae 100644
--- a/README.md
+++ b/README.md
@@ -1,101 +1,110 @@
 ## WxJava - 微信开发 Java SDK
+[![Github](https://img.shields.io/github/stars/binarywang/WxJava?logo=github&style=flat&label=Stars)](https://github.com/binarywang/WxJava)
+[![Gitee](https://gitee.com/binary/weixin-java-tools/badge/star.svg?theme=blue)](https://gitee.com/binary/weixin-java-tools)
+[![GitCode](https://gitcode.com/binary/WxJava/star/badge.svg)](https://gitcode.com/binary/WxJava)
 
-[![码云Gitee](https://gitee.com/binary/weixin-java-tools/badge/star.svg?theme=blue)](https://gitee.com/binary/weixin-java-tools)
-[![Github](https://img.shields.io/github/stars/Wechat-Group/WxJava?logo=github&style=flat)](https://github.com/Wechat-Group/WxJava)
-[![GitHub release](https://img.shields.io/github/release/Wechat-Group/WxJava.svg)](https://github.com/Wechat-Group/WxJava/releases)
-[![Maven Central](https://img.shields.io/maven-central/v/com.github.binarywang/wx-java.svg)](http://mvnrepository.com/artifact/com.github.binarywang/wx-java)
-[![Build Status](https://img.shields.io/circleci/project/github/Wechat-Group/WxJava/develop.svg?sanitize=true)](https://circleci.com/gh/Wechat-Group/WxJava/tree/develop)
+[![GitHub release](https://img.shields.io/github/release/binarywang/WxJava?label=Release)](https://github.com/binarywang/WxJava/releases)
+[![Maven Central](https://img.shields.io/maven-central/v/com.github.binarywang/wx-java?label=Maven)](https://central.sonatype.com/artifact/com.github.binarywang/wx-java/versions)
+[![Build Status](https://img.shields.io/circleci/project/github/binarywang/WxJava/develop.svg?sanitize=true&label=Build)](https://circleci.com/gh/binarywang/WxJava/tree/develop)
 [![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-支持-blue.svg)](https://www.jetbrains.com/?from=WxJava-weixin-java-tools)
 [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
 
-#### 微信`Java`开发工具包，支持包括微信支付、开放平台、公众号、企业微信、视频号、小程序等微信功能模块的后端开发。
+<div align="center">
+  <a href="https://hellogithub.com/repository/6de6147050c94db4aedfd7098d19f8d8" target="_blank">
+    <img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=6de6147050c94db4aedfd7098d19f8d8&claim_uid=mwKh0tILBfjlezR" alt="Featured｜HelloGitHub" width="250" height="54" />
+  </a>
+  <a href="https://trendshift.io/repositories/12152" target="_blank">
+    <img src="https://trendshift.io/api/badge/repositories/12152" alt="binarywang%2FWxJava | 趋势转变" width="250" height="55" />
+  </a>
+</div>
+
+### 微信`Java`开发工具包，支持包括微信支付、开放平台、公众号、企业微信、视频号、小程序等微信功能模块的后端开发。
 <div align="center">
   <b>特别赞助</b>
+  <table cellspacing="0" cellpadding="0" width="500">
+    <tr>
+      <td align="center" colspan="3">
+        <a href="http://www.ccflow.org/?from=wxjava" target="_blank">
+          <img height="120" src="https://ccfast.cc/AD/ccflow2.png" alt="ccflow">
+        </a>
+      </td>
+    </tr>
+    <tr>
+      <td align="center" colspan="2">
+        <a href="https://www.jeequan.com/product/jeepay.html" target="_blank">
+          <img height="120" src="https://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/wxjava_jeepay.png" alt="计全支付Jeepay,开源支付系统">
+        </a>
+      </td>
+      <td align="center">
+        <a href="https://www.mall4j.com/cn/?statId=9" target="_blank">
+          <img height="120" src="https://img.mall4j.com/mall.png" alt="Mall4j">
+        </a>
+      </td>
+    </tr>
+    <tr>
+      <td align="center">
+        <a href="http://mp.weixin.qq.com/mp/homepage?__biz=MzI3MzAwMzk4OA==&hid=1&sn=f31af3bf562b116b061c9ab4edf70b61&scene=18#wechat_redirect" target="_blank">
+          <img height="120" src="https://gitee.com/binary/weixin-java-tools/raw/develop/images/qrcodes/mp.png" alt="mp qrcode">
+        </a>
+      </td>
+      <td align="center">
+        <a href="https://www.diboot.com?from=wxjava" target="_blank">
+          <img height="120" src="https://www.diboot.com/img/diboot_ad.png" alt="diboot低代码开发平台">
+        </a>
+      </td>
+      <td align="center">
+        <a href="https://www.crmeb.com/xiazai" target="_blank">
+          <img height="120" src="https://crmebjavamer.oss-cn-beijing.aliyuncs.com/crmebimage/gitee/WechatIMG202.jpg" alt="ad">
+        </a>
+      </td>
+    </tr>
+  </table>
 </div>
-<table align="center" cellspacing="0" cellpadding="0" width="500">
-  <tr>
-    <td align="center" valign="middle" colspan="3">
-      <a href="http://www.ccflow.org/?from=wxjava" target="_blank">
-        <img height="120" src="https://ccfast.cc/AD/ccflow2.png" alt="ccflow">
-      </a>
-    </td>
-  </tr>
-  <tr>
-    <td align="center" valign="middle" colspan="3">
-      <a href="https://www.jeequan.com/product/jeepay.html" target="_blank">
-        <img height="120" src="https://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/wxjava_jeepay.png" alt="计全支付Jeepay,开源支付系统">
-      </a>
-    </td>
-  </tr>
-  <tr>
-    <td align="left" valign="middle">
-      <a href="http://mp.weixin.qq.com/mp/homepage?__biz=MzI3MzAwMzk4OA==&hid=1&sn=f31af3bf562b116b061c9ab4edf70b61&scene=18#wechat_redirect" target="_blank">
-        <img height="120" src="https://gitee.com/binary/weixin-java-tools/raw/develop/images/qrcodes/mp.png" alt="mp qrcode">
-      </a>
-    </td>
-    <td valign="middle">
-      <a href="https://www.diboot.com?from=wxjava" target="_blank">
-        <img height="120" src="https://www.diboot.com/img/diboot_ad.png" alt="diboot低代码开发平台"/>
-      </a>
-    </td>
-    <td align="right" valign="middle">
-      <a href="https://www.iyque.cn/" target="_blank">
-        <img height="120" src="https://iyque-1251309172.cos.ap-nanjing.myqcloud.com/advert/wxjava.jpg" alt="aliyun ad">
-      </a>
-    </td>
-  </tr>
-  <tr>
-    <td colspan="3" align="center">
-      <a href="https://hellogithub.com/repository/6de6147050c94db4aedfd7098d19f8d8" target="_blank">
-        <img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=6de6147050c94db4aedfd7098d19f8d8&claim_uid=mwKh0tILBfjlezR" 
-            alt="Featured｜HelloGitHub" style="width: 250px; height: 54px;" width="250" height="54" />
-      </a>
-    </td>
-  </tr>
-</table>
 
 ### 重要信息
-1. 项目合作洽谈请联系微信`binary0000`（在微信里自行搜索并添加好友，请注明来意，如有关于SDK问题需讨论请参考下文入群讨论，不要加此微信）。
-2. **2023-12-28 发布 [【4.6.0正式版】](https://mp.weixin.qq.com/s/9Hhc_8w-v7ogS_TEAsqfAg)**！
-3. 贡献源码可以参考视频：[【贡献源码全过程（上集）】](https://mp.weixin.qq.com/s/3xUZSATWwHR_gZZm207h7Q)、[【贡献源码全过程（下集）】](https://mp.weixin.qq.com/s/nyzJwVVoYSJ4hSbwyvTx9A) ，友情提供：[程序员小山与Bug](https://space.bilibili.com/473631007)
-4. 新手重要提示：本项目仅是一个SDK开发工具包，未提供Web实现，建议使用 `maven` 或 `gradle` 引用本项目即可使用本SDK提供的各种功能，详情可参考 **[【Demo项目】](demo.md)** 或本项目中的部分单元测试代码；
-5. 微信开发新手请务必阅读【开发文档】（[Gitee Wiki](https://gitee.com/binary/weixin-java-tools/wikis/Home) 或者 [Github Wiki](https://github.com/Wechat-Group/WxJava/wiki)）的常见问题部分，可以少走很多弯路，节省不少时间。
-6. 技术交流群：想获得QQ群/微信群/钉钉企业群等信息的同学，请使用微信扫描上面的微信公众号二维码关注 `WxJava` 后点击相关菜单即可获取加入方式，同时也可以在微信中搜索 `weixin-java-tools` 或 `WxJava` 后选择正确的公众号进行关注，该公众号会及时通知SDK相关更新信息，并不定期分享微信Java开发相关技术知识；
-7. 钉钉技术交流群：`32206329`（技术交流2群）, `30294972`（技术交流1群，目前已满），`35724728`（通知群，实时通知Github项目变更记录）。
-8. 微信开发新手或者Java开发新手在群内提问或新开Issue提问前，请先阅读[【提问的智慧】](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/master/README-zh_CN.md)，并确保已查阅过 [【开发文档Wiki】](https://github.com/wechat-group/WxJava/wiki) ，避免浪费大家的宝贵时间；
-9. 寻求帮助时需贴代码或大长串异常信息的，请利用 http://paste.ubuntu.com 
+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 
 
 --------------------------------
 ### 其他说明
 1. **阅读源码的同学请注意，本SDK为简化代码编译时加入了`lombok`支持，如果不了解`lombok`的话，请先学习下相关知识，比如可以阅读[此文章](https://mp.weixin.qq.com/s/cUc-bUcprycADfNepnSwZQ)；**
-2. 如有新功能需求，发现BUG，或者由于微信官方接口调整导致的代码问题，可以直接在[【Issues】](https://github.com/Wechat-Group/WxJava/issues)页提出issue，便于讨论追踪问题；
+2. 如有新功能需求，发现BUG，或者由于微信官方接口调整导致的代码问题，可以直接在[【Issues】](https://github.com/binarywang/WxJava/issues)页提出issue，便于讨论追踪问题；
 3. 如果需要贡献代码，请务必在提交PR之前先仔细阅读[【代码贡献指南】](CONTRIBUTING.md)，谢谢理解配合；
 4. 目前本`SDK`最新版本要求的`JDK`最低版本是`8`，使用`7`的同学可以使用`WxJava` `3.8.0`及以前版本，而还在使用`JDK`6的用户请参考[【此项目】]( https://github.com/binarywang/weixin-java-tools-for-jdk6) ，而其他更早的JDK版本则需要自己改造实现。
 5. [本项目在开源中国的页面](https://www.oschina.net/p/weixin-java-tools-new)，欢迎大家积极留言评分 🙂
-6. SDK开发文档请查阅 [【开发文档Wiki】](https://github.com/wechat-group/WxJava/wiki)，部分文档可能未能及时更新，如有发现，可以及时上报或者自行修改。
+6. SDK开发文档请查阅 [【开发文档Wiki】](https://github.com/binarywang/WxJava/wiki)，部分文档可能未能及时更新，如有发现，可以及时上报或者自行修改。
 7. **如果本开发工具包对您有所帮助，欢迎对我们的努力进行肯定，可以直接前往[【托管于码云的项目首页】](http://gitee.com/binary/weixin-java-tools)，在页尾部分找到“捐助”按钮进行打赏，多多益善 😄。非常感谢各位打赏和捐助的同学！**
 8. 各个模块的Javadoc可以在线查看：[weixin-java-miniapp](http://binary.ac.cn/weixin-java-miniapp-javadoc/)、[weixin-java-pay](http://binary.ac.cn/weixin-java-pay-javadoc/)、[weixin-java-mp](http://binary.ac.cn/weixin-java-mp-javadoc/)、[weixin-java-common](http://binary.ac.cn/weixin-java-common-javadoc/)、[weixin-java-cp](http://binary.ac.cn/weixin-java-cp-javadoc/)、[weixin-java-open](http://binary.ac.cn/weixin-java-open-javadoc/)
 9. 本SDK项目在以下代码托管网站同步更新:
 * 码云：https://gitee.com/binary/weixin-java-tools
-* GitHub：https://github.com/wechat-group/WxJava
+* GitHub：https://github.com/binarywang/WxJava
 
 ---------------------------------
 ### Maven 引用方式
-注意：最新版本（包括测试版）为 [![Maven Central](https://img.shields.io/maven-central/v/com.github.binarywang/wx-java.svg)](http://mvnrepository.com/artifact/com.github.binarywang/wx-java)，以下为最新正式版。
+注意：最新版本（包括测试版）为 [![Maven Central](https://img.shields.io/maven-central/v/com.github.binarywang/wx-java.svg)](https://central.sonatype.com/artifact/com.github.binarywang/wx-java/versions)，以下为最新正式版。
 
 ```xml
 <dependency>
   <groupId>com.github.binarywang</groupId>
   <artifactId>（不同模块参考下文）</artifactId>
-  <version>4.6.0</version>
+  <version>4.7.0</version>
 </dependency>
 ```
 
   - 微信小程序：`weixin-java-miniapp`   
   - 微信支付：`weixin-java-pay`
   - 微信开放平台：`weixin-java-open`   
-  - 公众号（包括订阅号和服务号）：`weixin-java-mp`    
-  - 企业号/企业微信：`weixin-java-cp`
+  - 微信公众号：`weixin-java-mp`    
+  - 企业微信：`weixin-java-cp`
+  - 微信视频号/微信小店：`weixin-java-channel`
 
 
 ---------------------------------
@@ -104,18 +113,22 @@
 <details>
 <summary>点此展开查看</summary>
   
-1. 本项目定为大约每两个月发布一次正式版（同时 `develop` 分支代码合并进入 `release` 分支），版本号格式为 `X.X.0`（如`2.1.0`，`2.2.0`等），遇到重大问题需修复会及时提交新版本，欢迎大家随时提交Pull Request；
-2. BUG修复和新特性一般会先发布成小版本作为临时测试版本（如`3.6.8.B`，即尾号不为0，并添加B，以区别于正式版），代码仅存在于 `develop` 分支中；
-3. 目前最新版本号为 [![Maven Central](https://img.shields.io/maven-central/v/com.github.binarywang/wx-java.svg)](http://mvnrepository.com/artifact/com.github.binarywang/wx-java) ，也可以通过访问链接 [【微信支付】](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.binarywang%22%20AND%20a%3A%22weixin-java-pay%22) 、[【微信小程序】](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.binarywang%22%20AND%20a%3A%22weixin-java-miniapp%22) 、[【公众号】](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.binarywang%22%20AND%20a%3A%22weixin-java-mp%22) 、[【企业微信】](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.binarywang%22%20AND%20a%3A%22weixin-java-cp%22)、[【开放平台】](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.github.binarywang%22%20AND%20a%3A%22weixin-java-open%22)
-分别查看所有最新的版本。 
+1. 本项目定为大约每半年左右发布一次正式版，遇到重大问题需修复会及时提交新版本，欢迎大家随时提交 `Pull Request`；
+2. 每次代码更新都会自动构建出新版本方便及时尝鲜，版本号格式为 `x.x.x-时间戳`;
+3. 发布正式版时，`develop` 分支代码合并进入 `release` 分支），版本号格式为 `X.X.0`（如`2.1.0`，`2.2.0`等）；
+4. 每隔一段时间后，会发布测试版本（如`3.6.8.B`，即尾号不为0，并添加B，以区别于正式版），代码仅存在于 `develop` 分支中；
+5. 目前最新版本号为 [![Maven Central](https://img.shields.io/maven-central/v/com.github.binarywang/wx-java.svg)](http://mvnrepository.com/artifact/com.github.binarywang/wx-java) ，也可以通过访问以下链接分别查看各个模块最新的版本： 
+[【微信支付】](https://central.sonatype.com/artifact/com.github.binarywang/weixin-java-pay/versions) 、[【小程序】](https://central.sonatype.com/artifact/com.github.binarywang/weixin-java-miniapp/versions) 、[【公众号】](https://central.sonatype.com/artifact/com.github.binarywang/weixin-java-mp/versions) 、[【企业微信】](https://central.sonatype.com/artifact/com.github.binarywang/weixin-java-cp/versions)、[【开放平台】](https://central.sonatype.com/artifact/com.github.binarywang/weixin-java-open/versions)、[【视频号】](https://central.sonatype.com/artifact/com.github.binarywang/weixin-java-channel/versions)
+
 
 </details>
 
 ----------------------------------
 ### 应用案例
-完整案例登记列表，请[【访问这里】](https://github.com/Wechat-Group/weixin-java-tools/issues/729)查看，欢迎登记更多的案例。
+完整案例登记列表，请[【访问这里】](https://github.com/binarywang/WxJava/issues/729)查看，欢迎登记更多的案例。
 
-以下为节选的部分案例：
+<details>
+<summary>以下为节选的部分案例， 点此展开查看</summary>
 
 #### 开源项目：
 - 基于微信公众号的签到、抽奖、发送弹幕程序：https://github.com/workcheng/weiya
@@ -178,26 +191,15 @@
 - 微信公众号管理系统：http://demo.joolun.com
 - 锐捷网络：Saleslink
 
+</details>
+
 ----------------------------------
 ### 贡献者列表
-特别感谢参与贡献的所有同学，所有贡献者列表请在[此处](https://github.com/Wechat-Group/WxJava/graphs/contributors)查看，欢迎大家继续踊跃贡献代码！
-<details>
-<summary>点击此处展开查看贡献次数最多的几位小伙伴</summary>
-
-1. [chanjarster (Daniel Qian)](https://github.com/chanjarster)
-2. [binarywang (Binary Wang)](https://github.com/binarywang)
-3. [007gzs](https://github.com/007gzs)
-4. [Silloy](https://github.com/silloy)
-5. [mgcnrx11](https://github.com/mgcnrx11)
-6. [0katekate0 (Wang_Wong)](https://github.com/0katekate0)
-7. [yuanqixun](https://github.com/yuanqixun)
-8. [kakotor](https://github.com/kakotor)
-9. [aimilin6688 (Jonk)](https://github.com/aimilin6688)
-10. [lkqm (Mario Luo)](https://github.com/lkqm)
-11. [kareanyi (MillerLin)](https://github.com/kareanyi)
-12. [Bincent (Hongbin.hsu)](https://gitee.com/bincent)
-</details>
+特别感谢参与贡献的所有同学，所有贡献者列表请在[此处](https://github.com/binarywang/WxJava/graphs/contributors)查看，欢迎大家继续踊跃贡献代码！
 
-### GitHub Stargazers over time
+<a href="https://github.com/binarywang/WxJava/graphs/contributors">
+  <img src="https://contrib.rocks/image?repo=binarywang/WxJava" />
+</a>
 
-[![Stargazers over time](https://starchart.cc/Wechat-Group/WxJava.svg)](https://starchart.cc/Wechat-Group/WxJava)     
+### GitHub Stargazers over time
+[![Star History Chart](https://api.star-history.com/svg?repos=binarywang/WxJava&type=Date)](https://star-history.com/#binarywang/WxJava&Date)
diff --git a/images/banners/ccflow.png b/images/banners/ccflow.png
deleted file mode 100644
index 1209739f6a..0000000000
Binary files a/images/banners/ccflow.png and /dev/null differ
diff --git a/images/banners/diboot.png b/images/banners/diboot.png
deleted file mode 100644
index c22d0b8ed8..0000000000
Binary files a/images/banners/diboot.png and /dev/null differ
diff --git a/images/banners/planB.jpg b/images/banners/planB.jpg
deleted file mode 100644
index 139957fbef..0000000000
Binary files a/images/banners/planB.jpg and /dev/null differ
diff --git a/others/mvnw b/others/mvnw
old mode 100644
new mode 100755
diff --git a/others/weixin-java-osgi/pom.xml b/others/weixin-java-osgi/pom.xml
index 67e4f42beb..b8531da88d 100644
--- a/others/weixin-java-osgi/pom.xml
+++ b/others/weixin-java-osgi/pom.xml
@@ -28,7 +28,7 @@
     <dependency>
       <groupId>com.thoughtworks.xstream</groupId>
       <artifactId>xstream</artifactId>
-      <version>1.4.19</version>
+      <version>1.4.21</version>
       <scope>provided</scope>
       <exclusions>
         <exclusion>
diff --git a/pom.xml b/pom.xml
index e66b89b436..a872188add 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.github.binarywang</groupId>
   <artifactId>wx-java</artifactId>
-  <version>4.6.7.B</version>
+  <version>4.7.7.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>
@@ -193,22 +197,24 @@
       <dependency>
         <groupId>com.thoughtworks.xstream</groupId>
         <artifactId>xstream</artifactId>
-        <version>1.4.20</version>
+        <version>1.4.21</version>
       </dependency>
       <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>
diff --git a/solon-plugins/pom.xml b/solon-plugins/pom.xml
index c6cc1c19cb..0c4fd35fa5 100644
--- a/solon-plugins/pom.xml
+++ b/solon-plugins/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>com.github.binarywang</groupId>
     <artifactId>wx-java</artifactId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.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>
diff --git a/solon-plugins/wx-java-channel-multi-solon-plugin/pom.xml b/solon-plugins/wx-java-channel-multi-solon-plugin/pom.xml
index 945a1bb7be..b229c12a0c 100644
--- a/solon-plugins/wx-java-channel-multi-solon-plugin/pom.xml
+++ b/solon-plugins/wx-java-channel-multi-solon-plugin/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <artifactId>wx-java-solon-plugins</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/solon-plugins/wx-java-channel-multi-solon-plugin/src/main/java/com/binarywang/solon/wxjava/channel/configuration/services/AbstractWxChannelConfiguration.java b/solon-plugins/wx-java-channel-multi-solon-plugin/src/main/java/com/binarywang/solon/wxjava/channel/configuration/services/AbstractWxChannelConfiguration.java
index 5521dff86a..eb80b5f7f3 100644
--- a/solon-plugins/wx-java-channel-multi-solon-plugin/src/main/java/com/binarywang/solon/wxjava/channel/configuration/services/AbstractWxChannelConfiguration.java
+++ b/solon-plugins/wx-java-channel-multi-solon-plugin/src/main/java/com/binarywang/solon/wxjava/channel/configuration/services/AbstractWxChannelConfiguration.java
@@ -8,6 +8,7 @@
 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;
@@ -59,7 +60,7 @@ protected WxChannelMultiServices wxChannelMultiServices(WxChannelMultiProperties
       WxChannelDefaultConfigImpl storage = this.wxChannelConfigStorage(wxChannelMultiProperties);
       this.configApp(storage, wxChannelSingleProperties);
       this.configHttp(storage, wxChannelMultiProperties.getConfigStorage());
-      WxChannelService wxChannelService = this.wxChannelService(storage, wxChannelMultiProperties, wxChannelSingleProperties.isUseStableAccessToken());
+      WxChannelService wxChannelService = this.wxChannelService(storage, wxChannelMultiProperties);
       services.addWxChannelService(tenantId, wxChannelService);
     }
     return services;
@@ -73,7 +74,7 @@ protected WxChannelMultiServices wxChannelMultiServices(WxChannelMultiProperties
    */
   protected abstract WxChannelDefaultConfigImpl wxChannelConfigStorage(WxChannelMultiProperties wxChannelMultiProperties);
 
-  public WxChannelService wxChannelService(WxChannelConfig wxChannelConfig, WxChannelMultiProperties wxChannelMultiProperties, boolean useStableAccessToken) {
+  public WxChannelService wxChannelService(WxChannelConfig wxChannelConfig, WxChannelMultiProperties wxChannelMultiProperties) {
     WxChannelMultiProperties.ConfigStorage storage = wxChannelMultiProperties.getConfigStorage();
     HttpClientType httpClientType = storage.getHttpClientType();
     WxChannelService wxChannelService;
@@ -82,7 +83,10 @@ public WxChannelService wxChannelService(WxChannelConfig wxChannelConfig, WxChan
 //        wxChannelService = new WxChannelServiceOkHttpImpl(false, false);
 //        break;
       case HTTP_CLIENT:
-        wxChannelService = new WxChannelServiceHttpClientImpl(useStableAccessToken, false);
+        wxChannelService = new WxChannelServiceHttpClientImpl();
+        break;
+      case HTTP_COMPONENTS:
+        wxChannelService = new WxChannelServiceHttpComponentsImpl();
         break;
       default:
         wxChannelService = new WxChannelServiceImpl();
@@ -108,6 +112,7 @@ private void configApp(WxChannelDefaultConfigImpl config, WxChannelSinglePropert
     String appSecret = wxChannelSingleProperties.getSecret();
     String token = wxChannelSingleProperties.getToken();
     String aesKey = wxChannelSingleProperties.getAesKey();
+    boolean useStableAccessToken = wxChannelSingleProperties.isUseStableAccessToken();
 
     config.setAppid(appId);
     config.setSecret(appSecret);
@@ -117,6 +122,7 @@ private void configApp(WxChannelDefaultConfigImpl config, WxChannelSinglePropert
     if (StringUtils.isNotBlank(aesKey)) {
       config.setAesKey(aesKey);
     }
+    config.setStableAccessToken(useStableAccessToken);
   }
 
   private void configHttp(WxChannelDefaultConfigImpl config, WxChannelMultiProperties.ConfigStorage storage) {
diff --git a/solon-plugins/wx-java-channel-multi-solon-plugin/src/main/java/com/binarywang/solon/wxjava/channel/enums/HttpClientType.java b/solon-plugins/wx-java-channel-multi-solon-plugin/src/main/java/com/binarywang/solon/wxjava/channel/enums/HttpClientType.java
index 1899e9e9f6..c34533c6d1 100644
--- a/solon-plugins/wx-java-channel-multi-solon-plugin/src/main/java/com/binarywang/solon/wxjava/channel/enums/HttpClientType.java
+++ b/solon-plugins/wx-java-channel-multi-solon-plugin/src/main/java/com/binarywang/solon/wxjava/channel/enums/HttpClientType.java
@@ -11,6 +11,10 @@ public enum HttpClientType {
    * HttpClient
    */
   HTTP_CLIENT,
+  /**
+   * HttpComponents
+   */
+  HTTP_COMPONENTS
   // WxChannelServiceOkHttpImpl 实现经测试无法正常完成业务固暂不支持OK_HTTP方式
 //  /**
 //   * OkHttp.
diff --git a/solon-plugins/wx-java-channel-solon-plugin/README.md b/solon-plugins/wx-java-channel-solon-plugin/README.md
new file mode 100644
index 0000000000..a7168a8edc
--- /dev/null
+++ b/solon-plugins/wx-java-channel-solon-plugin/README.md
@@ -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);
+  }
+}
+```
+
diff --git a/solon-plugins/wx-java-channel-solon-plugin/pom.xml b/solon-plugins/wx-java-channel-solon-plugin/pom.xml
index 562f61e2f7..471b9cf08a 100644
--- a/solon-plugins/wx-java-channel-solon-plugin/pom.xml
+++ b/solon-plugins/wx-java-channel-solon-plugin/pom.xml
@@ -3,7 +3,7 @@
   <parent>
     <artifactId>wx-java-solon-plugins</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/solon-plugins/wx-java-channel-solon-plugin/src/main/java/com/binarywang/solon/wxjava/channel/config/storage/AbstractWxChannelConfigStorageConfiguration.java b/solon-plugins/wx-java-channel-solon-plugin/src/main/java/com/binarywang/solon/wxjava/channel/config/storage/AbstractWxChannelConfigStorageConfiguration.java
index 41d002b419..2df3dbf23f 100644
--- a/solon-plugins/wx-java-channel-solon-plugin/src/main/java/com/binarywang/solon/wxjava/channel/config/storage/AbstractWxChannelConfigStorageConfiguration.java
+++ b/solon-plugins/wx-java-channel-solon-plugin/src/main/java/com/binarywang/solon/wxjava/channel/config/storage/AbstractWxChannelConfigStorageConfiguration.java
@@ -15,6 +15,7 @@ protected WxChannelDefaultConfigImpl config(WxChannelDefaultConfigImpl config, W
     config.setToken(StringUtils.trimToNull(properties.getToken()));
     config.setAesKey(StringUtils.trimToNull(properties.getAesKey()));
     config.setMsgDataFormat(StringUtils.trimToNull(properties.getMsgDataFormat()));
+    config.setStableAccessToken(properties.isUseStableAccessToken());
 
     WxChannelProperties.ConfigStorage configStorageProperties = properties.getConfigStorage();
     config.setHttpProxyHost(configStorageProperties.getHttpProxyHost());
diff --git a/solon-plugins/wx-java-channel-solon-plugin/src/main/java/com/binarywang/solon/wxjava/channel/properties/WxChannelProperties.java b/solon-plugins/wx-java-channel-solon-plugin/src/main/java/com/binarywang/solon/wxjava/channel/properties/WxChannelProperties.java
index f40aa82115..6562a02e9d 100644
--- a/solon-plugins/wx-java-channel-solon-plugin/src/main/java/com/binarywang/solon/wxjava/channel/properties/WxChannelProperties.java
+++ b/solon-plugins/wx-java-channel-solon-plugin/src/main/java/com/binarywang/solon/wxjava/channel/properties/WxChannelProperties.java
@@ -42,6 +42,11 @@ public class WxChannelProperties {
    */
   private String msgDataFormat = "JSON";
 
+  /**
+   * 是否使用稳定版 Access Token
+   */
+  private boolean useStableAccessToken = false;
+
   /**
    * 存储策略
    */
diff --git a/solon-plugins/wx-java-cp-multi-solon-plugin/pom.xml b/solon-plugins/wx-java-cp-multi-solon-plugin/pom.xml
index 24b9f65da8..ddb3062b6d 100644
--- a/solon-plugins/wx-java-cp-multi-solon-plugin/pom.xml
+++ b/solon-plugins/wx-java-cp-multi-solon-plugin/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <artifactId>wx-java-solon-plugins</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/solon-plugins/wx-java-cp-multi-solon-plugin/src/main/java/com/binarywang/solon/wxjava/cp_multi/configuration/services/AbstractWxCpConfiguration.java b/solon-plugins/wx-java-cp-multi-solon-plugin/src/main/java/com/binarywang/solon/wxjava/cp_multi/configuration/services/AbstractWxCpConfiguration.java
index 8710bba3ca..ada4ac504c 100644
--- a/solon-plugins/wx-java-cp-multi-solon-plugin/src/main/java/com/binarywang/solon/wxjava/cp_multi/configuration/services/AbstractWxCpConfiguration.java
+++ b/solon-plugins/wx-java-cp-multi-solon-plugin/src/main/java/com/binarywang/solon/wxjava/cp_multi/configuration/services/AbstractWxCpConfiguration.java
@@ -7,10 +7,7 @@
 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 @@ private WxCpService wxCpService(WxCpConfigStorage wxCpConfigStorage, WxCpMultiPr
       case HTTP_CLIENT:
         wxCpService = new WxCpServiceApacheHttpClientImpl();
         break;
+      case HTTP_COMPONENTS:
+        wxCpService = new WxCpServiceHttpComponentsImpl();
+        break;
       default:
         wxCpService = new WxCpServiceImpl();
         break;
diff --git a/solon-plugins/wx-java-cp-multi-solon-plugin/src/main/java/com/binarywang/solon/wxjava/cp_multi/properties/WxCpMultiProperties.java b/solon-plugins/wx-java-cp-multi-solon-plugin/src/main/java/com/binarywang/solon/wxjava/cp_multi/properties/WxCpMultiProperties.java
index 5544a92e00..821f885f98 100644
--- a/solon-plugins/wx-java-cp-multi-solon-plugin/src/main/java/com/binarywang/solon/wxjava/cp_multi/properties/WxCpMultiProperties.java
+++ b/solon-plugins/wx-java-cp-multi-solon-plugin/src/main/java/com/binarywang/solon/wxjava/cp_multi/properties/WxCpMultiProperties.java
@@ -117,6 +117,10 @@ public enum HttpClientType {
      * HttpClient
      */
     HTTP_CLIENT,
+    /**
+     * HttpComponents
+     */
+    HTTP_COMPONENTS,
     /**
      * OkHttp
      */
diff --git a/solon-plugins/wx-java-cp-solon-plugin/pom.xml b/solon-plugins/wx-java-cp-solon-plugin/pom.xml
index a9c1531e9e..d296c563b3 100644
--- a/solon-plugins/wx-java-cp-solon-plugin/pom.xml
+++ b/solon-plugins/wx-java-cp-solon-plugin/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <artifactId>wx-java-solon-plugins</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/solon-plugins/wx-java-miniapp-multi-solon-plugin/pom.xml b/solon-plugins/wx-java-miniapp-multi-solon-plugin/pom.xml
index ab78bd47e1..26af4bc4c3 100644
--- a/solon-plugins/wx-java-miniapp-multi-solon-plugin/pom.xml
+++ b/solon-plugins/wx-java-miniapp-multi-solon-plugin/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <artifactId>wx-java-solon-plugins</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/solon-plugins/wx-java-miniapp-solon-plugin/pom.xml b/solon-plugins/wx-java-miniapp-solon-plugin/pom.xml
index dd86bcba9a..2fa6ccfc81 100644
--- a/solon-plugins/wx-java-miniapp-solon-plugin/pom.xml
+++ b/solon-plugins/wx-java-miniapp-solon-plugin/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <artifactId>wx-java-solon-plugins</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/solon-plugins/wx-java-miniapp-solon-plugin/src/main/java/com/binarywang/solon/wxjava/miniapp/config/storage/AbstractWxMaConfigStorageConfiguration.java b/solon-plugins/wx-java-miniapp-solon-plugin/src/main/java/com/binarywang/solon/wxjava/miniapp/config/storage/AbstractWxMaConfigStorageConfiguration.java
index 9cc4fe161b..acc147a705 100644
--- a/solon-plugins/wx-java-miniapp-solon-plugin/src/main/java/com/binarywang/solon/wxjava/miniapp/config/storage/AbstractWxMaConfigStorageConfiguration.java
+++ b/solon-plugins/wx-java-miniapp-solon-plugin/src/main/java/com/binarywang/solon/wxjava/miniapp/config/storage/AbstractWxMaConfigStorageConfiguration.java
@@ -15,6 +15,7 @@ protected WxMaDefaultConfigImpl config(WxMaDefaultConfigImpl config, WxMaPropert
     config.setToken(StringUtils.trimToNull(properties.getToken()));
     config.setAesKey(StringUtils.trimToNull(properties.getAesKey()));
     config.setMsgDataFormat(StringUtils.trimToNull(properties.getMsgDataFormat()));
+    config.useStableAccessToken(properties.isUseStableAccessToken());
 
     WxMaProperties.ConfigStorage configStorageProperties = properties.getConfigStorage();
     config.setHttpProxyHost(configStorageProperties.getHttpProxyHost());
diff --git a/solon-plugins/wx-java-miniapp-solon-plugin/src/main/java/com/binarywang/solon/wxjava/miniapp/properties/WxMaProperties.java b/solon-plugins/wx-java-miniapp-solon-plugin/src/main/java/com/binarywang/solon/wxjava/miniapp/properties/WxMaProperties.java
index 5a993cf667..1c3e495f4e 100644
--- a/solon-plugins/wx-java-miniapp-solon-plugin/src/main/java/com/binarywang/solon/wxjava/miniapp/properties/WxMaProperties.java
+++ b/solon-plugins/wx-java-miniapp-solon-plugin/src/main/java/com/binarywang/solon/wxjava/miniapp/properties/WxMaProperties.java
@@ -45,6 +45,11 @@ public class WxMaProperties {
    */
   private String msgDataFormat;
 
+  /**
+   * 是否使用稳定版 Access Token
+   */
+  private boolean useStableAccessToken = false;
+
   /**
    * 存储策略
    */
diff --git a/solon-plugins/wx-java-mp-multi-solon-plugin/pom.xml b/solon-plugins/wx-java-mp-multi-solon-plugin/pom.xml
index 74cabd6fa8..2d56a7f793 100644
--- a/solon-plugins/wx-java-mp-multi-solon-plugin/pom.xml
+++ b/solon-plugins/wx-java-mp-multi-solon-plugin/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <artifactId>wx-java-solon-plugins</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/solon-plugins/wx-java-mp-solon-plugin/pom.xml b/solon-plugins/wx-java-mp-solon-plugin/pom.xml
index f5e6d523e7..8067190d89 100644
--- a/solon-plugins/wx-java-mp-solon-plugin/pom.xml
+++ b/solon-plugins/wx-java-mp-solon-plugin/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <artifactId>wx-java-solon-plugins</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/solon-plugins/wx-java-open-solon-plugin/pom.xml b/solon-plugins/wx-java-open-solon-plugin/pom.xml
index 14daefdd4a..54f3ced610 100644
--- a/solon-plugins/wx-java-open-solon-plugin/pom.xml
+++ b/solon-plugins/wx-java-open-solon-plugin/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <artifactId>wx-java-solon-plugins</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/solon-plugins/wx-java-pay-solon-plugin/pom.xml b/solon-plugins/wx-java-pay-solon-plugin/pom.xml
index 7e95ba7376..4d14403fff 100644
--- a/solon-plugins/wx-java-pay-solon-plugin/pom.xml
+++ b/solon-plugins/wx-java-pay-solon-plugin/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <artifactId>wx-java-solon-plugins</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/solon-plugins/wx-java-qidian-solon-plugin/pom.xml b/solon-plugins/wx-java-qidian-solon-plugin/pom.xml
index d22c4b2a39..d20f8ad204 100644
--- a/solon-plugins/wx-java-qidian-solon-plugin/pom.xml
+++ b/solon-plugins/wx-java-qidian-solon-plugin/pom.xml
@@ -3,7 +3,7 @@
   <parent>
     <artifactId>wx-java-solon-plugins</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/solon-plugins/wx-java-qidian-solon-plugin/src/main/java/com/binarywang/solon/wxjava/qidian/config/WxQidianStorageAutoConfiguration.java b/solon-plugins/wx-java-qidian-solon-plugin/src/main/java/com/binarywang/solon/wxjava/qidian/config/WxQidianStorageAutoConfiguration.java
index 7f78864226..a99a8178c9 100644
--- a/solon-plugins/wx-java-qidian-solon-plugin/src/main/java/com/binarywang/solon/wxjava/qidian/config/WxQidianStorageAutoConfiguration.java
+++ b/solon-plugins/wx-java-qidian-solon-plugin/src/main/java/com/binarywang/solon/wxjava/qidian/config/WxQidianStorageAutoConfiguration.java
@@ -18,11 +18,13 @@
 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 @@ private WxQidianConfigStorage defaultConfigStorage() {
   }
 
   private WxQidianConfigStorage jedisConfigStorage() {
-    Pool jedisPool;
+    Pool<Jedis> jedisPool;
     if (StringUtils.isNotEmpty(redisHost) || StringUtils.isNotEmpty(redisHost2)) {
       jedisPool = getJedisPool();
     } else {
@@ -104,7 +106,7 @@ private void setWxMpInfo(WxQidianDefaultConfigImpl config) {
     }
   }
 
-  private Pool getJedisPool() {
+  private Pool<Jedis> getJedisPool() {
     WxQidianProperties.ConfigStorage storage = wxQidianProperties.getConfigStorage();
     RedisProperties redis = storage.getRedis();
 
@@ -116,7 +118,7 @@ private Pool getJedisPool() {
       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());
diff --git a/spring-boot-starters/pom.xml b/spring-boot-starters/pom.xml
index 6abea0da05..6035f44a5a 100644
--- a/spring-boot-starters/pom.xml
+++ b/spring-boot-starters/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>com.github.binarywang</groupId>
     <artifactId>wx-java</artifactId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <packaging>pom</packaging>
   <artifactId>wx-java-spring-boot-starters</artifactId>
diff --git a/spring-boot-starters/wx-java-channel-multi-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-channel-multi-spring-boot-starter/pom.xml
index 336350866f..b82dcd765e 100644
--- a/spring-boot-starters/wx-java-channel-multi-spring-boot-starter/pom.xml
+++ b/spring-boot-starters/wx-java-channel-multi-spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <artifactId>wx-java-spring-boot-starters</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/spring-boot-starters/wx-java-channel-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/channel/configuration/services/AbstractWxChannelConfiguration.java b/spring-boot-starters/wx-java-channel-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/channel/configuration/services/AbstractWxChannelConfiguration.java
index 2e3f92a5f4..fab65363c4 100644
--- a/spring-boot-starters/wx-java-channel-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/channel/configuration/services/AbstractWxChannelConfiguration.java
+++ b/spring-boot-starters/wx-java-channel-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/channel/configuration/services/AbstractWxChannelConfiguration.java
@@ -59,7 +59,7 @@ protected WxChannelMultiServices wxChannelMultiServices(WxChannelMultiProperties
       WxChannelDefaultConfigImpl storage = this.wxChannelConfigStorage(wxChannelMultiProperties);
       this.configApp(storage, wxChannelSingleProperties);
       this.configHttp(storage, wxChannelMultiProperties.getConfigStorage());
-      WxChannelService wxChannelService = this.wxChannelService(storage, wxChannelMultiProperties, wxChannelSingleProperties.isUseStableAccessToken());
+      WxChannelService wxChannelService = this.wxChannelService(storage, wxChannelMultiProperties);
       services.addWxChannelService(tenantId, wxChannelService);
     }
     return services;
@@ -73,7 +73,7 @@ protected WxChannelMultiServices wxChannelMultiServices(WxChannelMultiProperties
    */
   protected abstract WxChannelDefaultConfigImpl wxChannelConfigStorage(WxChannelMultiProperties wxChannelMultiProperties);
 
-  public WxChannelService wxChannelService(WxChannelConfig wxChannelConfig, WxChannelMultiProperties wxChannelMultiProperties, boolean useStableAccessToken) {
+  public WxChannelService wxChannelService(WxChannelConfig wxChannelConfig, WxChannelMultiProperties wxChannelMultiProperties) {
     WxChannelMultiProperties.ConfigStorage storage = wxChannelMultiProperties.getConfigStorage();
     HttpClientType httpClientType = storage.getHttpClientType();
     WxChannelService wxChannelService;
@@ -82,7 +82,7 @@ public WxChannelService wxChannelService(WxChannelConfig wxChannelConfig, WxChan
 //        wxChannelService = new WxChannelServiceOkHttpImpl(false, false);
 //        break;
       case HTTP_CLIENT:
-        wxChannelService = new WxChannelServiceHttpClientImpl(useStableAccessToken, false);
+        wxChannelService = new WxChannelServiceHttpClientImpl();
         break;
       default:
         wxChannelService = new WxChannelServiceImpl();
@@ -108,6 +108,7 @@ private void configApp(WxChannelDefaultConfigImpl config, WxChannelSinglePropert
     String appSecret = wxChannelSingleProperties.getSecret();
     String token = wxChannelSingleProperties.getToken();
     String aesKey = wxChannelSingleProperties.getAesKey();
+    boolean useStableAccessToken = wxChannelSingleProperties.isUseStableAccessToken();
 
     config.setAppid(appId);
     config.setSecret(appSecret);
@@ -117,6 +118,7 @@ private void configApp(WxChannelDefaultConfigImpl config, WxChannelSinglePropert
     if (StringUtils.isNotBlank(aesKey)) {
       config.setAesKey(aesKey);
     }
+    config.setStableAccessToken(useStableAccessToken);
   }
 
   private void configHttp(WxChannelDefaultConfigImpl config, WxChannelMultiProperties.ConfigStorage storage) {
diff --git a/spring-boot-starters/wx-java-channel-spring-boot-starter/README.md b/spring-boot-starters/wx-java-channel-spring-boot-starter/README.md
new file mode 100644
index 0000000000..058a957359
--- /dev/null
+++ b/spring-boot-starters/wx-java-channel-spring-boot-starter/README.md
@@ -0,0 +1,103 @@
+# wx-java-channel-spring-boot-starter
+
+## 快速开始
+1. 引入依赖
+    ```xml
+    <dependencies>
+        <dependency>
+            <groupId>com.github.binarywang</groupId>
+            <artifactId>wx-java-channel-multi-spring-boot-starter</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>
+
+        <!-- 配置存储方式为redis_template 则引入spring data redis -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+    </dependencies>
+    ```
+2. 添加配置(application.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
+    
+    # redis_template 方式使用spring data redis配置
+    spring.data.redis.database=0
+    spring.data.redis.host=127.0.0.1
+    spring.data.redis.password=123456
+    spring.data.redis.port=6379
+    
+    # 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.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class DemoService {
+  @Autowired
+  private WxChannelService wxChannelService;
+
+  public String getShopInfo() throws WxErrorException {
+    // 获取店铺基本信息
+    ShopInfoResponse response = wxChannelService.getBasicService().getShopInfo();
+    // 此处为演示，如果要返回response的结果，建议自己封装一个VO，避免直接返回response
+    return JsonUtils.encode(response);
+  }
+}
+```
+
diff --git a/spring-boot-starters/wx-java-channel-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-channel-spring-boot-starter/pom.xml
index a752822853..833e2b5ac2 100644
--- a/spring-boot-starters/wx-java-channel-spring-boot-starter/pom.xml
+++ b/spring-boot-starters/wx-java-channel-spring-boot-starter/pom.xml
@@ -3,7 +3,7 @@
   <parent>
     <artifactId>wx-java-spring-boot-starters</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/spring-boot-starters/wx-java-channel-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/channel/config/storage/AbstractWxChannelConfigStorageConfiguration.java b/spring-boot-starters/wx-java-channel-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/channel/config/storage/AbstractWxChannelConfigStorageConfiguration.java
index a87028a1cd..d554c31eca 100644
--- a/spring-boot-starters/wx-java-channel-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/channel/config/storage/AbstractWxChannelConfigStorageConfiguration.java
+++ b/spring-boot-starters/wx-java-channel-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/channel/config/storage/AbstractWxChannelConfigStorageConfiguration.java
@@ -15,6 +15,7 @@ protected WxChannelDefaultConfigImpl config(WxChannelDefaultConfigImpl config, W
     config.setToken(StringUtils.trimToNull(properties.getToken()));
     config.setAesKey(StringUtils.trimToNull(properties.getAesKey()));
     config.setMsgDataFormat(StringUtils.trimToNull(properties.getMsgDataFormat()));
+    config.setStableAccessToken(properties.isUseStableAccessToken());
 
     WxChannelProperties.ConfigStorage configStorageProperties = properties.getConfigStorage();
     config.setHttpProxyHost(configStorageProperties.getHttpProxyHost());
diff --git a/spring-boot-starters/wx-java-channel-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/channel/properties/WxChannelProperties.java b/spring-boot-starters/wx-java-channel-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/channel/properties/WxChannelProperties.java
index 98f1f3b723..f2628b2ec3 100644
--- a/spring-boot-starters/wx-java-channel-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/channel/properties/WxChannelProperties.java
+++ b/spring-boot-starters/wx-java-channel-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/channel/properties/WxChannelProperties.java
@@ -41,6 +41,11 @@ public class WxChannelProperties {
    */
   private String msgDataFormat = "JSON";
 
+  /**
+   * 是否使用稳定版 Access Token
+   */
+  private boolean useStableAccessToken = false;
+
   /**
    * 存储策略
    */
diff --git a/spring-boot-starters/wx-java-cp-multi-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-cp-multi-spring-boot-starter/pom.xml
index e7926d86e1..a4f5004f0b 100644
--- a/spring-boot-starters/wx-java-cp-multi-spring-boot-starter/pom.xml
+++ b/spring-boot-starters/wx-java-cp-multi-spring-boot-starter/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <artifactId>wx-java-spring-boot-starters</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/spring-boot-starters/wx-java-cp-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-cp-spring-boot-starter/pom.xml
index 5021e02dc8..add193da7a 100644
--- a/spring-boot-starters/wx-java-cp-spring-boot-starter/pom.xml
+++ b/spring-boot-starters/wx-java-cp-spring-boot-starter/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <artifactId>wx-java-spring-boot-starters</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/pom.xml
index 09b02e63a3..2e1ab93137 100644
--- a/spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/pom.xml
+++ b/spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <artifactId>wx-java-spring-boot-starters</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/configuration/services/AbstractWxMaConfiguration.java b/spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/configuration/services/AbstractWxMaConfiguration.java
index 27ff84763b..50d4e89608 100644
--- a/spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/configuration/services/AbstractWxMaConfiguration.java
+++ b/spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/configuration/services/AbstractWxMaConfiguration.java
@@ -108,12 +108,12 @@ public WxMaService wxMaService(WxMaConfig wxMaConfig, WxMaMultiProperties wxMaMu
     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,6 +123,7 @@ private void configApp(WxMaDefaultConfigImpl config, WxMaSingleProperties corpPr
     if (StringUtils.isNotBlank(aesKey)) {
       config.setAesKey(aesKey);
     }
+    config.setMsgDataFormat(properties.getMsgDataFormat());
     config.useStableAccessToken(useStableAccessToken);
   }
 
diff --git a/spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/properties/WxMaSingleProperties.java b/spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/properties/WxMaSingleProperties.java
index 2842a2d970..57c0bfb30a 100644
--- a/spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/properties/WxMaSingleProperties.java
+++ b/spring-boot-starters/wx-java-miniapp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/properties/WxMaSingleProperties.java
@@ -33,6 +33,11 @@ public class WxMaSingleProperties implements Serializable {
    */
   private String aesKey;
 
+  /**
+   * 消息格式，XML或者JSON.
+   */
+  private String msgDataFormat;
+
   /**
    * 是否使用稳定版 Access Token
    */
diff --git a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md
index 82f6bdd8b1..cbf0b53925 100644
--- a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md
+++ b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md
@@ -10,12 +10,13 @@
     ```
 2. 添加配置(application.properties)
     ```properties
-    # 公众号配置(必填)
+    # 小程序配置(必填)
     wx.miniapp.appid = appId
     wx.miniapp.secret = @secret
     wx.miniapp.token = @token
     wx.miniapp.aesKey = @aesKey
     wx.miniapp.msgDataFormat = @msgDataFormat                  # 消息格式，XML或者JSON.
+    wx.miniapp.use-stable-access-token=@useStableAccessToken
     # 存储配置redis(可选)
     # 注意: 指定redis.host值后不会使用容器注入的redis连接(JedisPool)
     wx.miniapp.config-storage.type = Jedis                     # 配置类型: Memory(默认), Jedis, RedisTemplate
diff --git a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml
index dd59af8b92..a34a35e71d 100644
--- a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml
+++ b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/pom.xml
@@ -4,7 +4,7 @@
   <parent>
     <artifactId>wx-java-spring-boot-starters</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/config/storage/AbstractWxMaConfigStorageConfiguration.java b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/config/storage/AbstractWxMaConfigStorageConfiguration.java
index 6f44ac27ee..b691502de0 100644
--- a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/config/storage/AbstractWxMaConfigStorageConfiguration.java
+++ b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/config/storage/AbstractWxMaConfigStorageConfiguration.java
@@ -2,6 +2,8 @@
 
 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,11 +12,13 @@
 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());
 
     WxMaProperties.ConfigStorage configStorageProperties = properties.getConfigStorage();
     config.setHttpProxyHost(configStorageProperties.getHttpProxyHost());
@@ -24,6 +28,19 @@ protected WxMaDefaultConfigImpl config(WxMaDefaultConfigImpl config, WxMaPropert
       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;
diff --git a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/properties/WxMaProperties.java b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/properties/WxMaProperties.java
index b7ccb45374..729bd21228 100644
--- a/spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/properties/WxMaProperties.java
+++ b/spring-boot-starters/wx-java-miniapp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/miniapp/properties/WxMaProperties.java
@@ -44,6 +44,11 @@ public class WxMaProperties {
    */
   private String msgDataFormat;
 
+  /**
+   * 是否使用稳定版 Access Token
+   */
+  private boolean useStableAccessToken = false;
+
   /**
    * 存储策略
    */
@@ -107,6 +112,21 @@ public static class ConfigStorage {
      * </pre>
      */
     private int maxRetryTimes = 5;
+
+    /**
+     * 连接超时时间，单位毫秒
+     */
+    private int connectionTimeout = 5000;
+
+    /**
+     * 读数据超时时间，即socketTimeout，单位毫秒
+     */
+    private int soTimeout = 5000;
+
+    /**
+     * 从连接池获取链接的超时时间，单位毫秒
+     */
+    private int connectionRequestTimeout = 5000;
   }
 
 }
diff --git a/spring-boot-starters/wx-java-mp-multi-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-mp-multi-spring-boot-starter/pom.xml
index e76b4ec8b2..5268f7ef6b 100644
--- a/spring-boot-starters/wx-java-mp-multi-spring-boot-starter/pom.xml
+++ b/spring-boot-starters/wx-java-mp-multi-spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <artifactId>wx-java-spring-boot-starters</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/spring-boot-starters/wx-java-mp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/configuration/services/AbstractWxMpConfiguration.java b/spring-boot-starters/wx-java-mp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/configuration/services/AbstractWxMpConfiguration.java
index 4e55fb4580..1f431b645d 100644
--- a/spring-boot-starters/wx-java-mp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/configuration/services/AbstractWxMpConfiguration.java
+++ b/spring-boot-starters/wx-java-mp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/configuration/services/AbstractWxMpConfiguration.java
@@ -7,10 +7,7 @@
 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 WxMpService wxMpService(WxMpConfigStorage configStorage, WxMpMultiPropert
       case HTTP_CLIENT:
         wxMpService = new WxMpServiceHttpClientImpl();
         break;
+      case HTTP_COMPONENTS:
+        wxMpService = new WxMpServiceHttpComponentsImpl();
+        break;
       default:
         wxMpService = new WxMpServiceImpl();
         break;
diff --git a/spring-boot-starters/wx-java-mp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/WxMpMultiProperties.java b/spring-boot-starters/wx-java-mp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/WxMpMultiProperties.java
index c0d331382f..8b2fa58aa3 100644
--- a/spring-boot-starters/wx-java-mp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/WxMpMultiProperties.java
+++ b/spring-boot-starters/wx-java-mp-multi-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/WxMpMultiProperties.java
@@ -142,6 +142,10 @@ public enum HttpClientType {
      * HttpClient
      */
     HTTP_CLIENT,
+    /**
+     * HttpComponents
+     */
+    HTTP_COMPONENTS,
     /**
      * OkHttp
      */
diff --git a/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml
index 53cf73f350..211f7efd9c 100644
--- a/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml
+++ b/spring-boot-starters/wx-java-mp-spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <artifactId>wx-java-spring-boot-starters</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpStorageAutoConfiguration.java b/spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpStorageAutoConfiguration.java
index deb527e69f..4c0938454a 100644
--- a/spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpStorageAutoConfiguration.java
+++ b/spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/config/WxMpStorageAutoConfiguration.java
@@ -9,6 +9,8 @@
 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 @@ private void setWxMpInfo(WxMpDefaultConfigImpl config) {
     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());
diff --git a/spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/WxMpProperties.java b/spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/WxMpProperties.java
index a01fc0a521..377fb5b6ab 100644
--- a/spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/WxMpProperties.java
+++ b/spring-boot-starters/wx-java-mp-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/mp/properties/WxMpProperties.java
@@ -102,6 +102,21 @@ public static class ConfigStorage implements Serializable {
      */
     private String httpProxyPassword;
 
+    /**
+     * 连接超时时间，单位毫秒
+     */
+    private int connectionTimeout = 5000;
+
+    /**
+     * 读数据超时时间，即socketTimeout，单位毫秒
+     */
+    private int soTimeout = 5000;
+
+    /**
+     * 从连接池获取链接的超时时间，单位毫秒
+     */
+    private int connectionRequestTimeout = 5000;
+
   }
 
 }
diff --git a/spring-boot-starters/wx-java-open-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-open-spring-boot-starter/pom.xml
index ab481021ce..b027374de4 100644
--- a/spring-boot-starters/wx-java-open-spring-boot-starter/pom.xml
+++ b/spring-boot-starters/wx-java-open-spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <artifactId>wx-java-spring-boot-starters</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/spring-boot-starters/wx-java-open-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/open/config/storage/AbstractWxOpenConfigStorageConfiguration.java b/spring-boot-starters/wx-java-open-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/open/config/storage/AbstractWxOpenConfigStorageConfiguration.java
index ee0443c9ae..748ce80cd7 100644
--- a/spring-boot-starters/wx-java-open-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/open/config/storage/AbstractWxOpenConfigStorageConfiguration.java
+++ b/spring-boot-starters/wx-java-open-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/open/config/storage/AbstractWxOpenConfigStorageConfiguration.java
@@ -1,6 +1,8 @@
 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;
 
 /**
@@ -28,6 +30,20 @@ protected WxOpenInMemoryConfigStorage config(WxOpenInMemoryConfigStorage config,
     }
     config.setRetrySleepMillis(retrySleepMillis);
     config.setMaxRetryTimes(maxRetryTimes);
+    
+    // 设置自定义的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;
   }
 }
diff --git a/spring-boot-starters/wx-java-open-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/open/properties/WxOpenProperties.java b/spring-boot-starters/wx-java-open-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/open/properties/WxOpenProperties.java
index 641c57b005..af9e55876b 100644
--- a/spring-boot-starters/wx-java-open-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/open/properties/WxOpenProperties.java
+++ b/spring-boot-starters/wx-java-open-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/open/properties/WxOpenProperties.java
@@ -108,6 +108,21 @@ public static class ConfigStorage implements Serializable {
      */
     private int maxRetryTimes = 5;
 
+    /**
+     * 连接超时时间，单位毫秒
+     */
+    private int connectionTimeout = 5000;
+
+    /**
+     * 读数据超时时间，即socketTimeout，单位毫秒
+     */
+    private int soTimeout = 5000;
+
+    /**
+     * 从连接池获取链接的超时时间，单位毫秒
+     */
+    private int connectionRequestTimeout = 5000;
+
   }
 
   public enum StorageType {
diff --git a/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml
index 74919c49c3..e3d6b2d37d 100644
--- a/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml
+++ b/spring-boot-starters/wx-java-pay-spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <artifactId>wx-java-spring-boot-starters</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/spring-boot-starters/wx-java-pay-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/pay/config/WxPayAutoConfiguration.java b/spring-boot-starters/wx-java-pay-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/pay/config/WxPayAutoConfiguration.java
index 9a9672de1a..e401a8cfba 100644
--- a/spring-boot-starters/wx-java-pay-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/pay/config/WxPayAutoConfiguration.java
+++ b/spring-boot-starters/wx-java-pay-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/pay/config/WxPayAutoConfiguration.java
@@ -57,6 +57,8 @@ public WxPayService wxPayService() {
     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()));
 
     wxPayService.setConfig(payConfig);
     return wxPayService;
diff --git a/spring-boot-starters/wx-java-pay-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/pay/properties/WxPayProperties.java b/spring-boot-starters/wx-java-pay-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/pay/properties/WxPayProperties.java
index 232bd33c47..a1a8cc2297 100644
--- a/spring-boot-starters/wx-java-pay-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/pay/properties/WxPayProperties.java
+++ b/spring-boot-starters/wx-java-pay-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/pay/properties/WxPayProperties.java
@@ -73,7 +73,17 @@ public class WxPayProperties {
    * apiv3 商户apiclient_cert.pem
    */
   private String privateCertPath;
-  
+
+  /**
+   * 公钥ID
+   */
+  private String publicKeyId;
+
+  /**
+   * pub_key.pem证书文件的绝对路径或者以classpath:开头的类路径.
+   */
+  private String publicKeyPath;
+
   /**
    * 微信支付是否使用仿真测试环境.
    * 默认不使用
diff --git a/spring-boot-starters/wx-java-qidian-spring-boot-starter/pom.xml b/spring-boot-starters/wx-java-qidian-spring-boot-starter/pom.xml
index 27f8397a6b..3bfdd39383 100644
--- a/spring-boot-starters/wx-java-qidian-spring-boot-starter/pom.xml
+++ b/spring-boot-starters/wx-java-qidian-spring-boot-starter/pom.xml
@@ -3,7 +3,7 @@
   <parent>
     <artifactId>wx-java-spring-boot-starters</artifactId>
     <groupId>com.github.binarywang</groupId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
diff --git a/spring-boot-starters/wx-java-qidian-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/qidian/config/WxQidianStorageAutoConfiguration.java b/spring-boot-starters/wx-java-qidian-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/qidian/config/WxQidianStorageAutoConfiguration.java
index 80809fefce..01ba91b565 100644
--- a/spring-boot-starters/wx-java-qidian-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/qidian/config/WxQidianStorageAutoConfiguration.java
+++ b/spring-boot-starters/wx-java-qidian-spring-boot-starter/src/main/java/com/binarywang/spring/starter/wxjava/qidian/config/WxQidianStorageAutoConfiguration.java
@@ -20,6 +20,7 @@
 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 @@ private WxQidianConfigStorage defaultConfigStorage() {
   }
 
   private WxQidianConfigStorage jedisConfigStorage() {
-    Pool jedisPool;
+    Pool<Jedis> jedisPool;
     if (StringUtils.isNotEmpty(redisHost) || StringUtils.isNotEmpty(redisHost2)) {
       jedisPool = getJedisPool();
     } else {
@@ -136,7 +137,7 @@ private void setWxMpInfo(WxQidianDefaultConfigImpl config) {
     }
   }
 
-  private Pool getJedisPool() {
+  private Pool<Jedis> getJedisPool() {
     WxQidianProperties.ConfigStorage storage = wxQidianProperties.getConfigStorage();
     RedisProperties redis = storage.getRedis();
 
diff --git a/weixin-graal/pom.xml b/weixin-graal/pom.xml
index c429ba6187..0ddf797905 100644
--- a/weixin-graal/pom.xml
+++ b/weixin-graal/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>com.github.binarywang</groupId>
     <artifactId>wx-java</artifactId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
 
   <artifactId>weixin-graal</artifactId>
diff --git a/weixin-java-channel/pom.xml b/weixin-java-channel/pom.xml
index 8bce32841f..90c9788dab 100644
--- a/weixin-java-channel/pom.xml
+++ b/weixin-java-channel/pom.xml
@@ -6,15 +6,15 @@
   <parent>
     <groupId>com.github.binarywang</groupId>
     <artifactId>wx-java</artifactId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
 
   <artifactId>weixin-java-channel</artifactId>
   <name>WxJava - Channel Java SDK</name>
-  <description>微信视频号 Java SDK</description>
+  <description>微信视频号/微信小店 Java SDK</description>
 
   <properties>
-    <jackson.version>2.15.0</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>
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/BaseWxChannelMessageService.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/BaseWxChannelMessageService.java
index a4a2c4240e..a908da9479 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/BaseWxChannelMessageService.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/BaseWxChannelMessageService.java
@@ -20,9 +20,13 @@
 import me.chanjar.weixin.channel.bean.message.product.BrandMessage;
 import me.chanjar.weixin.channel.bean.message.product.CategoryAuditMessage;
 import me.chanjar.weixin.channel.bean.message.product.SpuAuditMessage;
+import me.chanjar.weixin.channel.bean.message.product.SpuStockMessage;
+import me.chanjar.weixin.channel.bean.message.store.CloseStoreMessage;
+import me.chanjar.weixin.channel.bean.message.store.NicknameUpdateMessage;
 import me.chanjar.weixin.channel.bean.message.supplier.SupplierItemMessage;
 import me.chanjar.weixin.channel.bean.message.vip.ExchangeInfoMessage;
 import me.chanjar.weixin.channel.bean.message.vip.UserInfoMessage;
+import me.chanjar.weixin.channel.bean.message.voucher.VoucherMessage;
 import me.chanjar.weixin.channel.message.WxChannelMessage;
 import me.chanjar.weixin.channel.message.WxChannelMessageRouterRule;
 import me.chanjar.weixin.common.session.WxSessionManager;
@@ -55,6 +59,7 @@ Object route(final WxChannelMessage message, final String content, final String
    * 订单下单
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -66,6 +71,7 @@ void orderNew(final OrderIdMessage message, final String content, final String a
    * 订单取消
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -77,6 +83,7 @@ void orderCancel(OrderCancelMessage message, final String content, final String
    * 订单支付成功
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -84,10 +91,23 @@ void orderCancel(OrderCancelMessage message, final String content, final String
   void orderPay(OrderPayMessage message, final String content, final String appId, final Map<String, Object> context,
     final WxSessionManager sessionManager);
 
+  /**
+   * 订单待发货
+   *
+   * @param message        消息
+   * @param content        消息原始内容
+   * @param appId          appId
+   * @param context        上下文
+   * @param sessionManager session管理器
+   */
+  void orderWaitShipping(OrderIdMessage message, final String content, final String appId, final Map<String, Object> context,
+    final WxSessionManager sessionManager);
+
   /**
    * 订单发货
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -99,6 +119,7 @@ void orderDelivery(OrderDeliveryMessage message, final String content, final Str
    * 订单确认收货
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -110,6 +131,7 @@ void orderConfirm(OrderConfirmMessage message, final String content, final Strin
    * 订单结算成功
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -121,6 +143,7 @@ void orderSettle(OrderSettleMessage message, final String content, final String
    * 订单其他信息更新
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -132,6 +155,7 @@ void orderExtInfoUpdate(OrderExtMessage message, final String content, final Str
    * 订单状态更新
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -143,6 +167,7 @@ void orderStatusUpdate(OrderStatusMessage message, final String content, final S
    * 商品审核结果
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -154,6 +179,7 @@ void spuAudit(SpuAuditMessage message, final String content, final String appId,
    * 商品系统下架通知
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -165,6 +191,7 @@ void spuStatusUpdate(SpuAuditMessage message, final String content, final String
    * 商品更新通知
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -172,10 +199,23 @@ void spuStatusUpdate(SpuAuditMessage message, final String content, final String
   void spuUpdate(SpuAuditMessage message, final String content, final String appId, final Map<String, Object> context,
     final WxSessionManager sessionManager);
 
+  /**
+   * 商品库存不足通知
+   *
+   * @param message        消息
+   * @param content        消息原始内容
+   * @param appId          appId
+   * @param context        上下文
+   * @param sessionManager session管理器
+   */
+  void stockNoEnough(SpuStockMessage message, final String content, final String appId,
+    final Map<String, Object> context, final WxSessionManager sessionManager);
+
   /**
    * 类目审核结果
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -187,6 +227,7 @@ void categoryAudit(CategoryAuditMessage message, final String content, final Str
    * 品牌更新
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -198,6 +239,7 @@ void brandUpdate(BrandMessage message, final String content, final String appId,
    * 售后单状态更新
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -209,6 +251,7 @@ void afterSaleStatusUpdate(AfterSaleMessage message, final String content, final
    * 纠纷回调
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -220,6 +263,7 @@ void complaintNotify(ComplaintMessage message, final String content, final Strin
    * 用户领券通知
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -231,6 +275,7 @@ void couponReceive(CouponReceiveMessage message, final String content, final Str
    * 创建优惠券通知
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -242,6 +287,7 @@ void couponCreate(CouponActionMessage message, final String content, final Strin
    * 优惠券删除通知
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -253,6 +299,7 @@ void couponDelete(CouponActionMessage message, final String content, final Strin
    * 优惠券过期通知
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -264,6 +311,7 @@ void couponExpire(CouponActionMessage message, final String content, final Strin
    * 更新优惠券信息通知
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -275,6 +323,7 @@ void couponUpdate(CouponActionMessage message, final String content, final Strin
    * 优惠券作废通知
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -286,6 +335,7 @@ void couponInvalid(CouponActionMessage message, final String content, final Stri
    * 用户优惠券过期通知
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -297,6 +347,7 @@ void userCouponExpire(UserCouponExpireMessage message, final String content, fin
    * 用户优惠券使用通知
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -308,6 +359,7 @@ void userCouponUse(UserCouponExpireMessage message, final String content, final
    * 用户优惠券返还通知
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -315,10 +367,22 @@ void userCouponUse(UserCouponExpireMessage message, final String content, final
   void userCouponUnuse(UserCouponExpireMessage message, final String content, final String appId,
     final Map<String, Object> context, final WxSessionManager sessionManager);
 
+  /**
+   * 发放团购优惠成功回调
+   *
+   * @param message        消息
+   * @param content        消息原始内容
+   * @param appId          appId
+   * @param context        上下文
+   * @param sessionManager session管理器
+   */
+  void voucherSendSucc(VoucherMessage message, final String content, final String appId,
+    final Map<String, Object> context, final WxSessionManager sessionManager);
   /**
    * 结算账户变更回调
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -330,6 +394,7 @@ void accountNotify(AccountNotifyMessage message, final String content, final Str
    * 提现回调
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -341,6 +406,7 @@ void withdrawNotify(WithdrawNotifyMessage message, final String content, final S
    * 提现二维码回调
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -352,6 +418,7 @@ void qrNotify(QrNotifyMessage message, final String content, final String appId,
    * 团长商品变更
    *
    * @param message        消息
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
@@ -420,12 +487,36 @@ void vipScoreUpdate(UserInfoMessage message, final String content, final String
   void vipScoreExchange(ExchangeInfoMessage message, final String content, final String appId,
                         final Map<String, Object> context, final WxSessionManager sessionManager);
 
+  /**
+   * 小店注销
+   *
+   * @param message        消息
+   * @param content        消息原始内容
+   * @param appId          appId
+   * @param context        上下文
+   * @param sessionManager session管理器
+   */
+  void closeStore(CloseStoreMessage message, final String content, final String appId,
+    final Map<String, Object> context, final WxSessionManager sessionManager);
+
+
+  /**
+   * 小店修改名称
+   *
+   * @param message        消息
+   * @param content        消息原始内容
+   * @param appId          appId
+   * @param context        上下文
+   * @param sessionManager session管理器
+   */
+  void updateNickname(NicknameUpdateMessage message, final String content, final String appId,
+    final Map<String, Object> context, final WxSessionManager sessionManager);
 
   /**
    * 默认消息处理
    *
    * @param message        消息
-   * @param content        内容
+   * @param content        消息原始内容
    * @param appId          appId
    * @param context        上下文
    * @param sessionManager session管理器
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/BaseWxChannelService.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/BaseWxChannelService.java
index f745ff3e41..07278da7ef 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/BaseWxChannelService.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/BaseWxChannelService.java
@@ -41,8 +41,7 @@ public interface BaseWxChannelService extends WxService {
    * <pre>
    * 获取access_token，本方法线程安全.
    * 且在多线程同时刷新时只刷新一次，避免超出2000次/日的调用次数上限
-   *
-   * 另：本service的所有方法都会在access_token过期是调用此方法
+   * 使用【稳定版接口】获取access_token时，限制【20次/日】，连续使用该模式时，请保证调用时间隔至少为30s，否则不会刷新
    *
    * 程序员在非必要情况下尽量不要主动调用此方法
    *
@@ -132,5 +131,5 @@ public interface BaseWxChannelService extends WxService {
    *
    * @return . request http
    */
-  RequestHttp getRequestHttp();
+  RequestHttp<?, ?> getRequestHttp();
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelAfterSaleService.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelAfterSaleService.java
index 418feab7ac..dedbf5e4f2 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelAfterSaleService.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelAfterSaleService.java
@@ -3,6 +3,7 @@
 
 import java.util.List;
 import me.chanjar.weixin.channel.bean.after.AfterSaleInfoResponse;
+import me.chanjar.weixin.channel.bean.after.AfterSaleListParam;
 import me.chanjar.weixin.channel.bean.after.AfterSaleListResponse;
 import me.chanjar.weixin.channel.bean.after.AfterSaleReasonResponse;
 import me.chanjar.weixin.channel.bean.after.AfterSaleRejectReasonResponse;
@@ -26,10 +27,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;
+
   /**
    * 获取售后单详情
    *
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelCategoryService.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelCategoryService.java
index ddbc99e5d4..0b357a5d1c 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelCategoryService.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelCategoryService.java
@@ -4,17 +4,20 @@
 import java.util.List;
 import me.chanjar.weixin.channel.bean.audit.AuditApplyResponse;
 import me.chanjar.weixin.channel.bean.audit.AuditResponse;
+import me.chanjar.weixin.channel.bean.audit.CategoryAuditInfo;
 import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
 import me.chanjar.weixin.channel.bean.category.CategoryDetailResult;
 import me.chanjar.weixin.channel.bean.category.CategoryQualificationResponse;
 import me.chanjar.weixin.channel.bean.category.PassCategoryResponse;
 import me.chanjar.weixin.channel.bean.category.ShopCategory;
+import me.chanjar.weixin.channel.bean.category.ShopCategoryResponse;
 import me.chanjar.weixin.common.error.WxErrorException;
 
 /**
  * 视频号小店 商品类目相关接口
  *
  * @author <a href="https://github.com/lixize">Zeyes</a>
+ * @see <a href="https://developers.weixin.qq.com/doc/store/API/category/new_old_diff.html">新旧类目树差异</a>
  */
 public interface WxChannelCategoryService {
 
@@ -30,12 +33,27 @@ public interface WxChannelCategoryService {
   /**
    * 获取商品类目列表(全量) 有频率限制
    *
-   * @param parentId 类目父id
+   * @param fCatId 类目父id
    * @return 类目列表
    *
    * @throws WxErrorException 异常
+   * @deprecated 接口返回更新，请使用 {@link #listAvailableCategories(String)}
    */
-  List<ShopCategory> listAvailableCategory(String parentId) throws WxErrorException;
+  @Deprecated
+  List<ShopCategory> listAvailableCategory(String fCatId) throws WxErrorException;
+
+  /**
+   * 获取可用的子类目详情
+   *
+   * 1.f_cat_id 为旧类目树中的非叶子类目，仅设置 cat_list 字段。
+   * 2.f_cat_id 为新类目树中的非叶子类目，仅设置 cat_list_v2 字段。
+   * 3.f_cat_id 为0，同时设置 cat_list 和 cat_list_v2 字段
+   *
+   * @param fCatId 父类目ID，可先填0获取根部类目
+   * @return 类目列表
+   * @throws WxErrorException 异常
+   */
+  ShopCategoryResponse listAvailableCategories(String fCatId) throws WxErrorException;
 
   /**
    * 获取类目信息
@@ -58,10 +76,23 @@ public interface WxChannelCategoryService {
    *
    * @throws WxErrorException 异常
    * @see WxChannelBasicService#uploadQualificationFile(File)
+   * @deprecated 请使用 {@link #addCategory(CategoryAuditInfo)}
    */
+  @Deprecated
   AuditApplyResponse addCategory(String level1, String level2, String level3, List<String> certificate)
     throws WxErrorException;
 
+  /**
+   * 上传类目资质
+   *
+   * @param info 类目资质信息
+   * @return 审核id
+   *
+   * @throws WxErrorException 异常
+   * @see WxChannelBasicService#uploadQualificationFile(File)
+   */
+  AuditApplyResponse addCategory(CategoryAuditInfo info) throws WxErrorException;
+
   /**
    * 取消类目提审
    *
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelCompassShopService.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelCompassShopService.java
new file mode 100644
index 0000000000..aa3a85fa74
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelCompassShopService.java
@@ -0,0 +1,126 @@
+package me.chanjar.weixin.channel.api;
+
+import me.chanjar.weixin.channel.bean.compass.shop.FinderAuthListResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.FinderListResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.FinderOverallResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.FinderProductListResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.FinderProductOverallResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.ShopLiveListResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.ShopOverallResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.ShopProductDataResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.ShopProductListResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.ShopSaleProfileDataResponse;
+import me.chanjar.weixin.common.error.WxErrorException;
+
+/**
+ * 视频号/微信小店 罗盘商家版服务
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+public interface WxChannelCompassShopService {
+
+  /**
+   * 获取电商概览数据
+   *
+   * @param ds 日期，格式 yyyyMMdd
+   * @return 电商概览数据
+   *
+   * @throws WxErrorException 异常
+   */
+  ShopOverallResponse getShopOverall(String ds) throws WxErrorException;
+
+  /**
+   * 获取授权视频号列表
+   *
+   * @return 获取授权视频号列表
+   *
+   * @throws WxErrorException 异常
+   */
+  FinderAuthListResponse getFinderAuthorizationList() throws WxErrorException;
+
+  /**
+   * 获取带货达人列表
+   *
+   * @param ds 日期，格式 yyyyMMdd
+   * @return 带货达人列表
+   *
+   * @throws WxErrorException 异常
+   */
+  FinderListResponse getFinderList(String ds) throws WxErrorException;
+
+  /**
+   * 获取带货数据概览
+   *
+   * @param ds 日期，格式 yyyyMMdd
+   * @return 带货数据概览
+   *
+   * @throws WxErrorException 异常
+   */
+  FinderOverallResponse getFinderOverall(String ds) throws WxErrorException;
+
+  /**
+   * 获取带货达人商品列表
+   *
+   * @param ds       日期，格式YYYYMMDD
+   * @param finderId 视频号ID
+   * @return 带货达人商品列表
+   *
+   * @throws WxErrorException 异常
+   */
+  FinderProductListResponse getFinderProductList(String ds, String finderId) throws WxErrorException;
+
+  /**
+   * 获取带货达人详情
+   *
+   * @param ds       日期，格式YYYYMMDD
+   * @param finderId 视频号ID
+   * @return 带货达人详情
+   *
+   * @throws WxErrorException 异常
+   */
+  FinderProductOverallResponse getFinderProductOverall(String ds, String finderId) throws WxErrorException;
+
+  /**
+   * 获取店铺开播列表
+   *
+   * @param ds       日期，格式YYYYMMDD
+   * @param finderId 视频号ID
+   * @return 店铺开播列表
+   *
+   * @throws WxErrorException 异常
+   */
+  ShopLiveListResponse getShopLiveList(String ds, String finderId) throws WxErrorException;
+
+  /**
+   * 获取商品详细信息
+   *
+   * @param ds        日期，格式YYYYMMDD
+   * @param productId 商品id
+   * @return 商品详细信息
+   *
+   * @throws WxErrorException 异常
+   */
+  ShopProductDataResponse getShopProductData(String ds, String productId) throws WxErrorException;
+
+  /**
+   * 获取商品列表
+   *
+   * @param ds 日期，格式YYYYMMDD
+   * @return 商品列表
+   *
+   * @throws WxErrorException 异常
+   */
+  ShopProductListResponse getShopProductList(String ds) throws WxErrorException;
+
+  /**
+   * 获取店铺人群数据
+   *
+   * @param ds   日期，格式 yyyyMMdd
+   * @param type 用户类型，1商品曝光用户 2商品点击用户 3购买用户 4首购用户 5复购用户
+   * @return 店铺人群数据
+   *
+   * @throws WxErrorException 异常
+   */
+  ShopSaleProfileDataResponse getShopSaleProfileData(String ds, Integer type) throws WxErrorException;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelOrderService.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelOrderService.java
index 6179510e78..7be0382bac 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelOrderService.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelOrderService.java
@@ -3,14 +3,17 @@
 import java.util.List;
 import me.chanjar.weixin.channel.bean.base.AddressInfo;
 import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+import me.chanjar.weixin.channel.bean.delivery.PackageAuditInfo;
 import me.chanjar.weixin.channel.bean.delivery.DeliveryCompanyResponse;
 import me.chanjar.weixin.channel.bean.delivery.DeliveryInfo;
 import me.chanjar.weixin.channel.bean.order.ChangeOrderInfo;
+import me.chanjar.weixin.channel.bean.order.DecodeSensitiveInfoResponse;
 import me.chanjar.weixin.channel.bean.order.DeliveryUpdateParam;
 import me.chanjar.weixin.channel.bean.order.OrderInfoResponse;
 import me.chanjar.weixin.channel.bean.order.OrderListParam;
 import me.chanjar.weixin.channel.bean.order.OrderListResponse;
 import me.chanjar.weixin.channel.bean.order.OrderSearchParam;
+import me.chanjar.weixin.channel.bean.order.VirtualTelNumberResponse;
 import me.chanjar.weixin.common.error.WxErrorException;
 
 /**
@@ -31,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;
+
   /**
    * 获取订单列表
    *
@@ -125,7 +139,7 @@ WxChannelBaseResponse updatePrice(String orderId, Integer expressFee, List<Chang
   WxChannelBaseResponse closeOrder(String orderId);
 
   /**
-   * 获取快递公司列表
+   * 获取快递公司列表-旧
    *
    * @return 快递公司列表
    *
@@ -133,6 +147,16 @@ WxChannelBaseResponse updatePrice(String orderId, Integer expressFee, List<Chang
    */
   DeliveryCompanyResponse listDeliveryCompany() throws WxErrorException;
 
+  /**
+   * 获取快递公司列表
+   *
+   * @param ewaybillOnly 是否仅返回支持电子面单功能的快递公司
+   * @return 快递公司列表
+   *
+   * @throws WxErrorException 异常
+   */
+  DeliveryCompanyResponse listDeliveryCompany(Boolean ewaybillOnly) throws WxErrorException;
+
   /**
    * 订单发货
    *
@@ -143,4 +167,37 @@ WxChannelBaseResponse updatePrice(String orderId, Integer expressFee, List<Chang
    * @throws WxErrorException 异常
    */
   WxChannelBaseResponse deliveryOrder(String orderId, List<DeliveryInfo> deliveryList) throws WxErrorException;
+
+  /**
+   * 上传生鲜质检信息<br />
+   *
+   * 注意事项：<br />
+   *  1. 非生鲜质检的订单不能进行上传 <br />
+   *  2. 图片url必须用图片上传接口获取 {@link WxChannelBasicService#uploadImg(int, String)}<br />
+   *
+   * @param orderId 订单id
+   * @param items   商品打包信息
+   * @return BaseResponse
+   *
+   * @throws WxErrorException 异常
+   */
+  WxChannelBaseResponse uploadFreshInspect(String orderId, List<PackageAuditInfo> items) throws WxErrorException;
+
+  /**
+   * 兑换虚拟号
+   *
+   * @param orderId 订单id
+   * @return 虚拟号信息
+   * @throws WxErrorException 异常
+   */
+  VirtualTelNumberResponse getVirtualTelNumber(String orderId) throws WxErrorException;
+
+  /**
+   * 解码订单包含的敏感数据
+   *
+   * @param orderId 订单id
+   * @return 解码结果
+   * @throws WxErrorException 异常
+   */
+  DecodeSensitiveInfoResponse decodeSensitiveInfo(String orderId) throws WxErrorException;
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelProductService.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelProductService.java
index b962b9ec85..7064adf70f 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelProductService.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelProductService.java
@@ -1,21 +1,29 @@
 package me.chanjar.weixin.channel.api;
 
 
+import java.util.List;
 import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
 import me.chanjar.weixin.channel.bean.limit.LimitTaskAddResponse;
 import me.chanjar.weixin.channel.bean.limit.LimitTaskListResponse;
 import me.chanjar.weixin.channel.bean.limit.LimitTaskParam;
+import me.chanjar.weixin.channel.bean.product.SkuStockBatchResponse;
 import me.chanjar.weixin.channel.bean.product.SkuStockResponse;
+import me.chanjar.weixin.channel.bean.product.SpuFastInfo;
 import me.chanjar.weixin.channel.bean.product.SpuGetResponse;
 import me.chanjar.weixin.channel.bean.product.SpuInfo;
 import me.chanjar.weixin.channel.bean.product.SpuListResponse;
+import me.chanjar.weixin.channel.bean.product.SpuUpdateInfo;
 import me.chanjar.weixin.channel.bean.product.SpuUpdateResponse;
+import me.chanjar.weixin.channel.bean.product.link.ProductH5UrlResponse;
+import me.chanjar.weixin.channel.bean.product.link.ProductQrCodeResponse;
+import me.chanjar.weixin.channel.bean.product.link.ProductTagLinkResponse;
 import me.chanjar.weixin.common.error.WxErrorException;
 
 /**
  * 视频号小店 商品服务接口
  *
  * @author <a href="https://github.com/lixize">Zeyes</a>
+ * @see <a href="https://developers.weixin.qq.com/doc/store/API/product/product_status.html">商品状态流转图</a>
  */
 public interface WxChannelProductService {
 
@@ -27,6 +35,28 @@ public interface WxChannelProductService {
    *
    * @throws WxErrorException 异常
    */
+  SpuUpdateResponse addProduct(SpuUpdateInfo info) throws WxErrorException;
+
+  /**
+   * 更新商品
+   *
+   * @param info 商品信息
+   * @return 返回商品的状态和id
+   *
+   * @throws WxErrorException 异常
+   */
+  SpuUpdateResponse updateProduct(SpuUpdateInfo info) throws WxErrorException;
+
+  /**
+   * 添加商品
+   *
+   * @param info 商品信息
+   * @return 返回商品的状态和id
+   *
+   * @throws WxErrorException 异常
+   * @deprecated 请使用 {@link #addProduct(SpuUpdateInfo)}
+   */
+  @Deprecated
   SpuUpdateResponse addProduct(SpuInfo info) throws WxErrorException;
 
   /**
@@ -36,15 +66,28 @@ public interface WxChannelProductService {
    * @return 返回商品的状态和id
    *
    * @throws WxErrorException 异常
+   * @deprecated 请使用 {@link #updateProduct(SpuUpdateInfo)}
    */
+  @Deprecated
   SpuUpdateResponse updateProduct(SpuInfo info) throws WxErrorException;
 
+  /**
+   * 免审更新商品
+   *
+   * @param info 商品信息
+   * @return 返回商品的状态和id
+   *
+   * @throws WxErrorException 异常
+   */
+  WxChannelBaseResponse updateProductAuditFree(SpuFastInfo info) throws WxErrorException;
+
   /**
    * 更新商品库存 （仅对edit_status != 2 的商品适用，其他状态的商品无法通过该接口修改库存）
    *
    * @param productId 内部商品ID
    * @param skuId     内部sku_id
    * @param diffType  修改类型 1增加 2减少 3设置
+   *                  建议使用1或2，不建议使用3，因为使用3在高并发场景可能会出现预期外表现
    * @param num       增加、减少或者设置的库存值
    * @return WxChannelBaseResponse
    *
@@ -127,6 +170,42 @@ WxChannelBaseResponse updateStock(String productId, String skuId, Integer diffTy
    */
   SkuStockResponse getSkuStock(String productId, String skuId) throws WxErrorException;
 
+  /**
+   * 批量获取库存信息 （单次请求不能超过50个商品ID）
+   *
+   * @param productIds 商品ID列表
+   * @return 库存信息
+   * @throws WxErrorException 异常
+   */
+  SkuStockBatchResponse getSkuStockBatch(List<String> productIds) throws WxErrorException;
+
+  /**
+   * 获取商品H5链接
+   *
+   * @param productId 商品ID
+   * @return 商品H5链接
+   * @throws WxErrorException 异常
+   */
+  ProductH5UrlResponse getProductH5Url(String productId) throws WxErrorException;
+
+  /**
+   * 获取商品二维码
+   *
+   * @param productId 商品ID
+   * @return 商品二维码
+   * @throws WxErrorException 异常
+   */
+  ProductQrCodeResponse getProductQrCode(String productId) throws WxErrorException;
+
+  /**
+   * 获取商品口令
+   *
+   * @param productId 商品ID
+   * @return 商品口令
+   * @throws WxErrorException 异常
+   */
+  ProductTagLinkResponse getProductTagLink(String productId) throws WxErrorException;
+
   /**
    * 添加限时抢购任务
    *
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelService.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelService.java
index 48d82206b3..50a029c196 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelService.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelService.java
@@ -91,6 +91,27 @@ public interface WxChannelService extends BaseWxChannelService {
    */
   WxChannelFundService getFundService();
 
+  /**
+   * 主页管理服务
+   *
+   * @return 主页管理服务
+   */
+  WxStoreHomePageService getHomePageService();
+
+  /**
+   * 合作账号服务
+   *
+   * @return 团长合作服务
+   */
+  WxStoreCooperationService getCooperationService();
+
+  /**
+   * 视频号/微信小店 罗盘商家版服务
+   *
+   * @return 罗盘商家版服务
+   */
+  WxChannelCompassShopService getCompassShopService();
+
   /**
    * 优选联盟-团长合作达人管理服务
    *
@@ -140,7 +161,6 @@ public interface WxChannelService extends BaseWxChannelService {
    */
   WxAssistantService getAssistantService();
 
-
   /**
    * 会员功能
    *
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelVipService.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelVipService.java
index 0909844f06..4100659200 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelVipService.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxChannelVipService.java
@@ -45,11 +45,11 @@ public interface WxChannelVipService {
    *
    * @param needPhoneNumber the need phone number
    * @param pageNum         the page num
-   * @param PageSize        the page size
+   * @param pageSize        the page size
    * @return the vip list
    * @throws WxErrorException the wx error exception
    */
-  VipListResponse getVipList(Boolean needPhoneNumber, Integer pageNum, Integer PageSize) throws WxErrorException;
+  VipListResponse getVipList(Boolean needPhoneNumber, Integer pageNum, Integer pageSize) throws WxErrorException;
 
   /**
    * 获取用户积分
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxLeaguePromoterService.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxLeaguePromoterService.java
index 8a8ffb9acf..60cf112271 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxLeaguePromoterService.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxLeaguePromoterService.java
@@ -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;
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxStoreCooperationService.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxStoreCooperationService.java
new file mode 100644
index 0000000000..96d2ff5f8d
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxStoreCooperationService.java
@@ -0,0 +1,70 @@
+package me.chanjar.weixin.channel.api;
+
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+import me.chanjar.weixin.channel.bean.cooperation.CooperationListResponse;
+import me.chanjar.weixin.channel.bean.cooperation.CooperationQrCodeResponse;
+import me.chanjar.weixin.channel.bean.cooperation.CooperationStatusResponse;
+import me.chanjar.weixin.common.error.WxErrorException;
+
+/**
+ * 微信小店 合作账号相关接口
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ * @see <a href="https://developers.weixin.qq.com/doc/store/API/cooperation/">合作账号状态机</a>
+ */
+public interface WxStoreCooperationService {
+
+  /**
+   * 获取合作账号列表
+   *
+   * @param sharerType 合作账号类型 2公众号 3小程序
+   * @return 合作账号列表
+   *
+   * @throws WxErrorException 异常
+   */
+  CooperationListResponse listCooperation(Integer sharerType) throws WxErrorException;
+
+  /**
+   * 获取合作账号状态
+   *
+   * @param sharerId   合作账号id 公众号: gh_开头id 小程序: appid
+   * @param sharerType 合作账号类型 2公众号 3小程序
+   * @return 合作账号状态
+   *
+   * @throws WxErrorException 异常
+   */
+  CooperationStatusResponse getCooperationStatus(String sharerId, Integer sharerType) throws WxErrorException;
+
+  /**
+   * 生成合作账号邀请二维码
+   *
+   * @param sharerId   合作账号id 公众号: gh_开头id 小程序: appid
+   * @param sharerType 合作账号类型 2公众号 3小程序
+   * @return 二维码
+   *
+   * @throws WxErrorException 异常
+   */
+  CooperationQrCodeResponse generateQrCode(String sharerId, Integer sharerType) throws WxErrorException;
+
+  /**
+   * 取消合作账号邀请
+   *
+   * @param sharerId   合作账号id 公众号: gh_开头id 小程序: appid
+   * @param sharerType 合作账号类型 2公众号 3小程序
+   * @return WxChannelBaseResponse
+   *
+   * @throws WxErrorException 异常
+   */
+  WxChannelBaseResponse cancelInvitation(String sharerId, Integer sharerType) throws WxErrorException;
+
+  /**
+   * 解绑合作账号
+   *
+   * @param sharerId   合作账号id 公众号: gh_开头id 小程序: appid
+   * @param sharerType 合作账号类型 2公众号 3小程序
+   * @return WxChannelBaseResponse
+   *
+   * @throws WxErrorException 异常
+   */
+  WxChannelBaseResponse unbind(String sharerId, Integer sharerType) throws WxErrorException;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxStoreHomePageService.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxStoreHomePageService.java
new file mode 100644
index 0000000000..bd11e471b3
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/WxStoreHomePageService.java
@@ -0,0 +1,188 @@
+package me.chanjar.weixin.channel.api;
+
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+import me.chanjar.weixin.channel.bean.home.background.BackgroundApplyResponse;
+import me.chanjar.weixin.channel.bean.home.background.BackgroundGetResponse;
+import me.chanjar.weixin.channel.bean.home.banner.BannerApplyResponse;
+import me.chanjar.weixin.channel.bean.home.banner.BannerGetResponse;
+import me.chanjar.weixin.channel.bean.home.banner.BannerInfo;
+import me.chanjar.weixin.channel.bean.home.tree.TreeProductEditInfo;
+import me.chanjar.weixin.channel.bean.home.tree.TreeProductListInfo;
+import me.chanjar.weixin.channel.bean.home.tree.TreeProductListResponse;
+import me.chanjar.weixin.channel.bean.home.tree.TreeShowGetResponse;
+import me.chanjar.weixin.channel.bean.home.tree.TreeShowInfo;
+import me.chanjar.weixin.channel.bean.home.tree.TreeShowSetResponse;
+import me.chanjar.weixin.channel.bean.home.window.WindowProductSettingResponse;
+import me.chanjar.weixin.common.error.WxErrorException;
+
+/**
+ * 微信小店 主页管理相关接口
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+public interface WxStoreHomePageService {
+
+  /**
+   * 添加分类关联的商品
+   *
+   * @param info 商品分类以及商品id
+   * @return BaseResponse
+   *
+   * @throws WxErrorException 异常
+   */
+  WxChannelBaseResponse addTreeProduct(TreeProductEditInfo info) throws WxErrorException;
+
+  /**
+   * 删除分类关联的商品
+   *
+   * @param info 商品分类以及商品id
+   * @return BaseResponse
+   *
+   * @throws WxErrorException 异常
+   */
+  WxChannelBaseResponse delTreeProduct(TreeProductEditInfo info) throws WxErrorException;
+
+  /**
+   * 获取分类关联的商品ID列表
+   *
+   * @param info 分类id、分页大小、分页上下文
+   * @return 商品id、分页上下文
+   *
+   * @throws WxErrorException 异常
+   */
+  TreeProductListResponse getTreeProductList(TreeProductListInfo info) throws WxErrorException;
+
+  /**
+   * 设置展示在店铺主页的商品分类
+   *
+   * @param info 分类id
+   * @return 商品分类审核结果
+   *
+   * @throws WxErrorException 异常
+   */
+  TreeShowSetResponse setShowTree(TreeShowInfo info) throws WxErrorException;
+
+  /**
+   * 获取展示在店铺主页的商品分类
+   *
+   * @return 商品分类信息
+   *
+   * @throws WxErrorException 异常
+   */
+  TreeShowGetResponse getShowTree() throws WxErrorException;
+
+  /**
+   * 获取主页展示商品列表
+   *
+   * @param pageSize 分页大小
+   * @param nextKey  分页上下文
+   * @return WindowProductSettingResponse
+   *
+   * @throws WxErrorException 异常
+   */
+  WindowProductSettingResponse listWindowProduct(Integer pageSize, String nextKey) throws WxErrorException;
+
+  /**
+   * 删除主页展示商品
+   *
+   * @param productId 商品id
+   * @param indexNum  商品重新排序后的新序号，最大移动步长为500（即新序号与当前序号的距离小于500）
+   * @return BaseResponse
+   *
+   * @throws WxErrorException 异常
+   */
+  WxChannelBaseResponse reorderWindowProduct(String productId, Integer indexNum) throws WxErrorException;
+
+  /**
+   * 隐藏小店主页商品
+   *
+   * @param productId 商品id
+   * @param setHide   是否隐藏。1-隐藏，0-取消隐藏
+   * @return BaseResponse
+   *
+   * @throws WxErrorException 异常
+   */
+  WxChannelBaseResponse hideWindowProduct(String productId, Integer setHide) throws WxErrorException;
+
+  /**
+   * 置顶小店主页商品
+   *
+   * @param productId 商品id
+   * @param setTop    是否顶置。1-置顶，0-取消置顶
+   * @return BaseResponse
+   *
+   * @throws WxErrorException 异常
+   */
+  WxChannelBaseResponse topWindowProduct(String productId, Integer setTop) throws WxErrorException;
+
+  /**
+   * 提交背景图申请
+   *
+   * @param imgUrl 图片链接。请务必使用接口上传图片（参数resp_type=1），并将返回的img_url填入此处，不接受其他任何格式的图片url。
+   *               若url曾经做过转换（url前缀为mmecimage.cn/p/），则可以直接提交。
+   * @return 申请编号
+   *
+   * @throws WxErrorException 异常
+   * @see WxChannelBasicService#uploadImg(int, String)
+   */
+  BackgroundApplyResponse applyBackground(String imgUrl) throws WxErrorException;
+
+  /**
+   * 查询背景图
+   *
+   * @return 背景图信息
+   * @throws WxErrorException 异常
+   */
+  BackgroundGetResponse getBackground() throws WxErrorException;
+
+  /**
+   * 撤销主页背景图申请
+   *
+   * @param applyId 申请编号
+   * @return BaseResponse
+   * @throws WxErrorException 异常
+   */
+  WxChannelBaseResponse cancelBackground(Integer applyId) throws WxErrorException;
+
+  /**
+   * 清空主页背景图并撤销流程中的申请
+   *
+   * @return BaseResponse
+   * @throws WxErrorException 异常
+   */
+  WxChannelBaseResponse removeBackground() throws WxErrorException;
+
+  /**
+   * 提交精选展示位申请
+   *
+   * @param info 展示位信息
+   * @return 申请编号
+   * @throws WxErrorException 异常
+   */
+  BannerApplyResponse applyBanner(BannerInfo info) throws WxErrorException;
+
+  /**
+   * 查询精选展示位
+   *
+   * @return 展示位信息
+   * @throws WxErrorException 异常
+   */
+  BannerGetResponse getBanner() throws WxErrorException;
+
+  /**
+   * 撤销精选展示位申请
+   *
+   * @param applyId 申请编号
+   * @return BaseResponse
+   * @throws WxErrorException 异常
+   */
+  WxChannelBaseResponse cancelBanner(Integer applyId) throws WxErrorException;
+
+  /**
+   * 清空精选展示位并撤销流程中的申请
+   *
+   * @return BaseResponse
+   * @throws WxErrorException 异常
+   */
+  WxChannelBaseResponse removeBanner() throws WxErrorException;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/BaseWxChannelMessageServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/BaseWxChannelMessageServiceImpl.java
index 46837deba8..0aeabdd7c6 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/BaseWxChannelMessageServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/BaseWxChannelMessageServiceImpl.java
@@ -23,10 +23,14 @@
 import me.chanjar.weixin.channel.bean.message.product.BrandMessage;
 import me.chanjar.weixin.channel.bean.message.product.CategoryAuditMessage;
 import me.chanjar.weixin.channel.bean.message.product.SpuAuditMessage;
+import me.chanjar.weixin.channel.bean.message.product.SpuStockMessage;
 import me.chanjar.weixin.channel.bean.message.sharer.SharerChangeMessage;
+import me.chanjar.weixin.channel.bean.message.store.CloseStoreMessage;
+import me.chanjar.weixin.channel.bean.message.store.NicknameUpdateMessage;
 import me.chanjar.weixin.channel.bean.message.supplier.SupplierItemMessage;
 import me.chanjar.weixin.channel.bean.message.vip.ExchangeInfoMessage;
 import me.chanjar.weixin.channel.bean.message.vip.UserInfoMessage;
+import me.chanjar.weixin.channel.bean.message.voucher.VoucherMessage;
 import me.chanjar.weixin.channel.message.WxChannelMessage;
 import me.chanjar.weixin.channel.message.WxChannelMessageRouter;
 import me.chanjar.weixin.channel.message.WxChannelMessageRouterRule;
@@ -62,6 +66,8 @@ protected void addDefaultRule() {
     this.addRule(SpuAuditMessage.class, PRODUCT_SPU_STATUS_UPDATE, this::spuStatusUpdate);
     /* 商品更新 */
     this.addRule(SpuAuditMessage.class, PRODUCT_SPU_UPDATE, this::spuUpdate);
+    /* 商品库存不足 */
+    this.addRule(SpuStockMessage.class, PRODUCT_STOCK_NO_ENOUGH, this::stockNoEnough);
     /* 类目审核结果 */
     this.addRule(CategoryAuditMessage.class, PRODUCT_CATEGORY_AUDIT, this::categoryAudit);
     /* 订单下单 */
@@ -70,6 +76,8 @@ protected void addDefaultRule() {
     this.addRule(OrderCancelMessage.class, ORDER_CANCEL, this::orderCancel);
     /* 订单支付成功 */
     this.addRule(OrderPayMessage.class, ORDER_PAY, this::orderPay);
+    /* 订单待发货 */
+    this.addRule(OrderIdMessage.class, ORDER_WAIT_SHIPPING, this::orderWaitShipping);
     /* 订单发货 */
     this.addRule(OrderDeliveryMessage.class, ORDER_DELIVER, this::orderDelivery);
     /* 订单确认收货 */
@@ -102,6 +110,8 @@ protected void addDefaultRule() {
     this.addRule(UserCouponExpireMessage.class, USER_COUPON_UNUSE, this::userCouponUnuse);
     /* 优惠券返还通知 */
     this.addRule(UserCouponExpireMessage.class, USER_COUPON_USE, this::userCouponUse);
+    /* 发放团购优惠成功通知 */
+    this.addRule(VoucherMessage.class, VOUCHER_SEND_SUCC, this::voucherSendSucc);
     /* 结算账户变更回调 */
     this.addRule(AccountNotifyMessage.class, ACCOUNT_NOTIFY, this::accountNotify);
     /* 提现回调 */
@@ -111,7 +121,6 @@ protected void addDefaultRule() {
     /* 团长 */
     this.addRule(SupplierItemMessage.class, SUPPLIER_ITEM_UPDATE, this::supplierItemUpdate);
 
-
     /* 用户加入会员 */
     this.addRule(UserInfoMessage.class, USER_VIP_JOIN, false, this::vipJoin);
     /* 用户注销会员 */
@@ -123,9 +132,13 @@ protected void addDefaultRule() {
     /* 用户积分兑换 */
     this.addRule(ExchangeInfoMessage.class, USER_VIP_SCORE_EXCHANGE, false, this::vipScoreExchange);
 
-
     /* 分享员变更 */
     this.addRule(SharerChangeMessage.class,SHARER_CHANGE,false,this::sharerChange);
+
+    /* 小店注销 */
+    this.addRule(CloseStoreMessage.class, CLOSE_STORE, this::closeStore);
+    /* 小店修改名称 */
+    this.addRule(NicknameUpdateMessage.class, SET_SHOP_NICKNAME, this::updateNickname);
   }
 
   /**
@@ -144,6 +157,7 @@ protected <T extends WxChannelMessage> void addRule(Class<T> clazz, String event
       consumer.accept(message, content, appId, context, sessionManager);
       return "success";
     });
+    rule.setNext(true);
     this.addRule(rule);
   }
 
@@ -181,6 +195,12 @@ public void orderPay(OrderPayMessage message, String content, String appId,
     log.info("订单支付成功:{}", JsonUtils.encode(message));
   }
 
+  @Override
+  public void orderWaitShipping(OrderIdMessage message, String content, String appId,
+    Map<String, Object> context, WxSessionManager sessionManager) {
+    log.info("订单待发货:{}", JsonUtils.encode(message));
+  }
+
   @Override
   public void orderDelivery(OrderDeliveryMessage message, String content, String appId,
     Map<String, Object> context, WxSessionManager sessionManager) {
@@ -229,6 +249,12 @@ public void spuUpdate(SpuAuditMessage message, String content, String appId,
     log.info("商品更新:{}", JsonUtils.encode(message));
   }
 
+  @Override
+  public void stockNoEnough(SpuStockMessage message, String content, String appId,
+          Map<String, Object> context, WxSessionManager sessionManager) {
+    log.info("商品库存不足:{}", JsonUtils.encode(message));
+  }
+
   @Override
   public void categoryAudit(CategoryAuditMessage message, String content, String appId,
     Map<String, Object> context, WxSessionManager sessionManager) {
@@ -307,6 +333,12 @@ public void userCouponUnuse(UserCouponExpireMessage message, String content, Str
     log.info("用户优惠券取消使用:{}", JsonUtils.encode(message));
   }
 
+  @Override
+  public void voucherSendSucc(VoucherMessage message, String content, String appId,
+          Map<String, Object> context, WxSessionManager sessionManager) {
+    log.info("发放团购优惠成功:{}", JsonUtils.encode(message));
+  }
+
   @Override
   public void accountNotify(AccountNotifyMessage message, String content, String appId,
     Map<String, Object> context, WxSessionManager sessionManager) {
@@ -344,22 +376,44 @@ public void sharerChange(WxChannelMessage message, String content, String appId,
   }
 
   @Override
-  public abstract void vipJoin(UserInfoMessage message, String content, String appId,
-                               Map<String, Object> context, WxSessionManager sessionManager);
+  public void vipJoin(UserInfoMessage message, String content, String appId,
+                               Map<String, Object> context, WxSessionManager sessionManager) {
+    log.info("用户加入会员:{}", JsonUtils.encode(message));
+  }
 
   @Override
-  public abstract void vipClose(UserInfoMessage message, String content, String appId,
-                                      Map<String, Object> context, WxSessionManager sessionManager);
+  public void vipClose(UserInfoMessage message, String content, String appId,
+                                      Map<String, Object> context, WxSessionManager sessionManager) {
+    log.info("用户注销会员:{}", JsonUtils.encode(message));
+  }
 
   @Override
-  public abstract void vipGradeUpdate(UserInfoMessage message, String content, String appId,
-                                            Map<String, Object> context, WxSessionManager sessionManager);
+  public void vipGradeUpdate(UserInfoMessage message, String content, String appId,
+                                            Map<String, Object> context, WxSessionManager sessionManager) {
+    log.info("用户等级信息更新:{}", JsonUtils.encode(message));
+  }
 
   @Override
-  public abstract void vipScoreUpdate(UserInfoMessage message, String content, String appId,
-                                            Map<String, Object> context, WxSessionManager sessionManager);
+  public void vipScoreUpdate(UserInfoMessage message, String content, String appId,
+                                            Map<String, Object> context, WxSessionManager sessionManager) {
+    log.info("用户积分更新:{}", JsonUtils.encode(message));
+  }
+
+  @Override
+  public void vipScoreExchange(ExchangeInfoMessage message, String content, String appId,
+                                              Map<String, Object> context, WxSessionManager sessionManager) {
+    log.info("用户积分兑换:{}", JsonUtils.encode(message));
+  }
 
   @Override
-  public abstract void vipScoreExchange(ExchangeInfoMessage message, String content, String appId,
-                                              Map<String, Object> context, WxSessionManager sessionManager);
+  public void closeStore(CloseStoreMessage message, String content, String appId,
+    Map<String, Object> context, WxSessionManager sessionManager) {
+    log.info("小店注销:{}", JsonUtils.encode(message));
+  }
+
+  @Override
+  public void updateNickname(NicknameUpdateMessage message, String content, String appId,
+    Map<String, Object> context, WxSessionManager sessionManager) {
+    log.info("小店修改名称:{}", JsonUtils.encode(message));
+  }
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/BaseWxChannelServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/BaseWxChannelServiceImpl.java
index c9f874c99e..1a608e1f6a 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/BaseWxChannelServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/BaseWxChannelServiceImpl.java
@@ -47,6 +47,9 @@ public abstract class BaseWxChannelServiceImpl<H, P> implements WxChannelService
   private final WxChannelCouponService couponService = new WxChannelCouponServiceImpl(this);
   private final WxChannelSharerService sharerService = new WxChannelSharerServiceImpl(this);
   private final WxChannelFundService fundService = new WxChannelFundServiceImpl(this);
+  private WxStoreHomePageService homePageService = null;
+  private WxStoreCooperationService cooperationService = null;
+  private WxChannelCompassShopService compassShopService = null;
   private WxLeagueWindowService leagueWindowService = null;
   private WxLeagueSupplierService leagueSupplierService = null;
   private WxLeaguePromoterService leaguePromoterService = null;
@@ -54,18 +57,16 @@ public abstract class BaseWxChannelServiceImpl<H, P> implements WxChannelService
   private WxLeadComponentService leadComponentService = null;
   private WxFinderLiveService finderLiveService = null;
   private WxAssistantService assistantService = null;
-  private WxChannelVipService vipService = new WxChannelVipServiceImpl(this);
-  private final WxChannelCompassFinderService compassFinderService =
-    new WxChannelCompassFinderServiceImpl(this);
-  private final WxChannelLiveDashboardService liveDashboardService =
-    new WxChannelLiveDashboardServiceImpl(this);
+  private WxChannelVipService vipService = null;
+  private WxChannelCompassFinderService compassFinderService = null;
+  private WxChannelLiveDashboardService liveDashboardService = null;
 
   protected WxChannelConfig config;
   private int retrySleepMillis = 1000;
   private int maxRetryTimes = 5;
 
   @Override
-  public RequestHttp getRequestHttp() {
+  public RequestHttp<H, P> getRequestHttp() {
     return this;
   }
 
@@ -74,7 +75,7 @@ public boolean checkSignature(String timestamp, String nonce, String signature)
     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;
     }
   }
@@ -99,9 +100,14 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
           return this.getConfig().getAccessToken();
         }
       } while (!locked);
-      String response = doGetAccessTokenRequest();
+      String response;
+      if (getConfig().isStableAccessToken()) {
+        response = doGetStableAccessTokenRequest(forceRefresh);
+      } else {
+        response = doGetAccessTokenRequest();
+      }
       return extractAccessToken(response);
-    } catch (WxErrorException | InterruptedException e) {
+    } catch (IOException | InterruptedException e) {
       throw new WxRuntimeException(e);
     } finally {
       if (locked) {
@@ -113,10 +119,18 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
   /**
    * 通过网络请求获取AccessToken
    *
-   * @return .
-   * @throws IOException .
+   * @return AccessToken
+   * @throws IOException IOException
+   */
+  protected abstract String doGetAccessTokenRequest() throws IOException;
+
+  /**
+   * 通过网络请求获取稳定版AccessToken
+   *
+   * @return Stable AccessToken
+   * @throws IOException IOException
    */
-  protected abstract String doGetAccessTokenRequest() throws WxErrorException;
+  protected abstract String doGetStableAccessTokenRequest(boolean forceRefresh) throws IOException;
 
   @Override
   public String get(String url, String queryParam) throws WxErrorException {
@@ -262,9 +276,9 @@ protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E
    * @throws WxErrorException 异常
    */
   protected String extractAccessToken(String resultContent) throws WxErrorException {
-    log.info("resultContent: " + resultContent);
+    log.debug("access-token response: {}", resultContent);
     WxChannelConfig config = this.getConfig();
-    WxError error = WxError.fromJson(resultContent, WxType.MiniApp);
+    WxError error = WxError.fromJson(resultContent, WxType.Channel);
     if (error.getErrorCode() != 0) {
       throw new WxErrorException(error);
     }
@@ -354,6 +368,30 @@ public WxChannelFundService getFundService() {
     return fundService;
   }
 
+  @Override
+  public synchronized WxStoreHomePageService getHomePageService() {
+    if (homePageService == null) {
+      homePageService = new WxStoreHomePageServiceImpl(this);
+    }
+    return homePageService;
+  }
+
+  @Override
+  public synchronized WxStoreCooperationService getCooperationService() {
+    if (cooperationService == null) {
+      cooperationService = new WxStoreCooperationServiceImpl(this);
+    }
+    return cooperationService;
+  }
+
+  @Override
+  public synchronized WxChannelCompassShopService getCompassShopService() {
+    if (compassShopService == null) {
+      compassShopService = new WxChannelCompassShopServiceImpl(this);
+    }
+    return compassShopService;
+  }
+
   @Override
   public synchronized WxLeagueWindowService getLeagueWindowService() {
     if (leagueWindowService == null) {
@@ -387,7 +425,7 @@ public synchronized WxLeagueProductService getLeagueProductService() {
   }
 
   @Override
-  public WxLeadComponentService getLeadComponentService() {
+  public synchronized WxLeadComponentService getLeadComponentService() {
     if (leadComponentService == null) {
       leadComponentService = new WxLeadComponentServiceImpl(this);
     }
@@ -395,7 +433,7 @@ public WxLeadComponentService getLeadComponentService() {
   }
 
   @Override
-  public WxFinderLiveService getFinderLiveService() {
+  public synchronized WxFinderLiveService getFinderLiveService() {
     if (finderLiveService == null) {
       finderLiveService = new WxFinderLiveServiceImpl(this);
     }
@@ -403,7 +441,7 @@ public WxFinderLiveService getFinderLiveService() {
   }
 
   @Override
-  public WxAssistantService getAssistantService() {
+  public synchronized WxAssistantService getAssistantService() {
     if (assistantService == null) {
       assistantService = new WxAssistantServiceImpl(this) {
       };
@@ -412,14 +450,27 @@ public WxAssistantService getAssistantService() {
   }
 
   @Override
-  public WxChannelVipService getVipService() {
+  public synchronized WxChannelVipService getVipService() {
+    if (vipService == null) {
+      vipService = new WxChannelVipServiceImpl(this);
+    }
     return vipService;
   }
 
   @Override
-  public WxChannelCompassFinderService getCompassFinderService() { return compassFinderService; }
+  public synchronized WxChannelCompassFinderService getCompassFinderService() {
+    if (compassFinderService == null) {
+      compassFinderService = new WxChannelCompassFinderServiceImpl(this);
+    }
+    return compassFinderService;
+  }
 
   @Override
-  public WxChannelLiveDashboardService getLiveDashboardService() { return liveDashboardService; }
+  public synchronized WxChannelLiveDashboardService getLiveDashboardService() {
+    if (liveDashboardService == null) {
+      liveDashboardService = new WxChannelLiveDashboardServiceImpl(this);
+    }
+    return liveDashboardService;
+  }
 
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxAssistantServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxAssistantServiceImpl.java
index 20572c5ef0..55be5abcca 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxAssistantServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxAssistantServiceImpl.java
@@ -28,7 +28,7 @@
 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, "{}");
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelAddressServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelAddressServiceImpl.java
index 53b9eb4d7a..20cf128559 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelAddressServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelAddressServiceImpl.java
@@ -29,9 +29,9 @@
 public class WxChannelAddressServiceImpl implements WxChannelAddressService {
 
   /** 微信商店服务 */
-  private final BaseWxChannelServiceImpl shopService;
+  private final BaseWxChannelServiceImpl<?, ?> shopService;
 
-  public WxChannelAddressServiceImpl(BaseWxChannelServiceImpl shopService) {
+  public WxChannelAddressServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
     this.shopService = shopService;
   }
 
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelAfterSaleServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelAfterSaleServiceImpl.java
index a4be86f28d..4e314d52fa 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelAfterSaleServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelAfterSaleServiceImpl.java
@@ -23,16 +23,22 @@
 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);
   }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelBasicServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelBasicServiceImpl.java
index cac5e9e513..6eb699da23 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelBasicServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelBasicServiceImpl.java
@@ -31,9 +31,9 @@
 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 ChannelImageInfo uploadImg(int respType, String imgUrl) throws WxErrorExc
   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 ChannelImageInfo uploadImg(int respType, File file, int height, int width
   @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);
     }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelBrandServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelBrandServiceImpl.java
index 19aadcc06e..c6c476b116 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelBrandServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelBrandServiceImpl.java
@@ -33,9 +33,9 @@
 public class WxChannelBrandServiceImpl implements WxChannelBrandService {
 
   /** 微信商店服务 */
-  private final BaseWxChannelServiceImpl shopService;
+  private final BaseWxChannelServiceImpl<?, ?> shopService;
 
-  public WxChannelBrandServiceImpl(BaseWxChannelServiceImpl shopService) {
+  public WxChannelBrandServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
     this.shopService = shopService;
   }
 
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelCategoryServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelCategoryServiceImpl.java
index 52fdf3cdf8..23cd839848 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelCategoryServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelCategoryServiceImpl.java
@@ -37,9 +37,9 @@
 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 List<ShopCategory> listAvailableCategory(String parentId) throws WxErrorE
     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 + "}";
@@ -66,13 +66,21 @@ public List<ShopCategory> listAvailableCategory(String parentId) throws WxErrorE
     return response.getCategories();
   }
 
+  @Override
+  public ShopCategoryResponse listAvailableCategories(String fCatId) throws WxErrorException {
+    String reqJson = "{\"f_cat_id\": " + fCatId + "}";
+    String resJson = (String) shopService.executeWithoutLog(SimplePostRequestExecutor.create(shopService),
+      AVAILABLE_CATEGORY_URL, reqJson);
+    return ResponseUtils.decode(resJson, ShopCategoryResponse.class);
+  }
+
   @Override
   public CategoryDetailResult getCategoryDetail(String id) throws WxErrorException {
     Long catId = null;
     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 + "}";
@@ -89,7 +97,11 @@ public AuditApplyResponse addCategory(String level1, String level2, String level
       Long l1 = Long.parseLong(level1);
       Long l2 = Long.parseLong(level2);
       Long l3 = Long.parseLong(level3);
-      CategoryAuditInfo categoryInfo = new CategoryAuditInfo(l1, l2, l3, certificate);
+      CategoryAuditInfo categoryInfo = new CategoryAuditInfo();
+      categoryInfo.setLevel1(l1);
+      categoryInfo.setLevel2(l2);
+      categoryInfo.setLevel3(l3);
+      categoryInfo.setCertificates(certificate);
       reqJson = JsonUtils.encode(new CategoryAuditRequest(categoryInfo));
     } catch (Throwable e) {
       log.error("微信请求异常", e);
@@ -98,6 +110,13 @@ public AuditApplyResponse addCategory(String level1, String level2, String level
     return ResponseUtils.decode(resJson, AuditApplyResponse.class);
   }
 
+  @Override
+  public AuditApplyResponse addCategory(CategoryAuditInfo info) throws WxErrorException {
+    String reqJson = JsonUtils.encode(new CategoryAuditRequest(info));
+    String resJson = shopService.post(ADD_CATEGORY_URL, reqJson);
+    return ResponseUtils.decode(resJson, AuditApplyResponse.class);
+  }
+
   @Override
   public WxChannelBaseResponse cancelCategoryAudit(String auditId) throws WxErrorException {
     String resJson = shopService.post(CANCEL_CATEGORY_AUDIT_URL, "{\"audit_id\": \"" + auditId + "\"}");
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelCompassFinderServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelCompassFinderServiceImpl.java
index 34bead89d6..c80345aef2 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelCompassFinderServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelCompassFinderServiceImpl.java
@@ -2,6 +2,7 @@
 
 import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.channel.api.WxChannelCompassFinderService;
+import me.chanjar.weixin.channel.bean.compass.CompassFinderBaseParam;
 import me.chanjar.weixin.channel.bean.compass.finder.*;
 import me.chanjar.weixin.channel.util.ResponseUtils;
 import me.chanjar.weixin.common.error.WxErrorException;
@@ -19,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 {
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelCompassShopServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelCompassShopServiceImpl.java
new file mode 100644
index 0000000000..3a593a691f
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelCompassShopServiceImpl.java
@@ -0,0 +1,116 @@
+package me.chanjar.weixin.channel.api.impl;
+
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.CompassShop.FINDER_AUTH_LIST_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.CompassShop.FINDER_LIST_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.CompassShop.GET_FINDER_OVERALL_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.CompassShop.GET_FINDER_PRODUCT_LIST_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.CompassShop.GET_FINDER_PRODUCT_OVERALL_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.CompassShop.GET_LIVE_LIST_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.CompassShop.GET_SHOP_OVERALL_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.CompassShop.GET_SHOP_PRODUCT_DATA_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.CompassShop.GET_SHOP_PRODUCT_LIST_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.CompassShop.GET_SHOP_SALE_PROFILE_DATA_URL;
+
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.channel.api.WxChannelCompassShopService;
+import me.chanjar.weixin.channel.bean.compass.CompassFinderBaseParam;
+import me.chanjar.weixin.channel.bean.compass.shop.CompassFinderIdParam;
+import me.chanjar.weixin.channel.bean.compass.shop.FinderAuthListResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.FinderListResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.FinderOverallResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.FinderProductListResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.FinderProductOverallResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.ShopLiveListResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.ShopOverallResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.ShopProductDataParam;
+import me.chanjar.weixin.channel.bean.compass.shop.ShopProductDataResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.ShopProductListResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.ShopSaleProfileDataParam;
+import me.chanjar.weixin.channel.bean.compass.shop.ShopSaleProfileDataResponse;
+import me.chanjar.weixin.channel.util.ResponseUtils;
+import me.chanjar.weixin.common.error.WxErrorException;
+
+/**
+ * 视频号/微信小店 罗盘商家版 服务实现
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Slf4j
+public class WxChannelCompassShopServiceImpl implements WxChannelCompassShopService {
+
+  /**
+   * 微信商店服务
+   */
+  private final BaseWxChannelServiceImpl<?, ?> shopService;
+
+  public WxChannelCompassShopServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {this.shopService = shopService;}
+
+  @Override
+  public ShopOverallResponse getShopOverall(String ds) throws WxErrorException {
+    CompassFinderBaseParam param = new CompassFinderBaseParam(ds);
+    String resJson = shopService.post(GET_SHOP_OVERALL_URL, param);
+    return ResponseUtils.decode(resJson, ShopOverallResponse.class);
+  }
+
+  @Override
+  public FinderAuthListResponse getFinderAuthorizationList() throws WxErrorException {
+    String resJson = shopService.post(FINDER_AUTH_LIST_URL, "{}");
+    return ResponseUtils.decode(resJson, FinderAuthListResponse.class);
+  }
+
+  @Override
+  public FinderListResponse getFinderList(String ds) throws WxErrorException {
+    CompassFinderBaseParam param = new CompassFinderBaseParam(ds);
+    String resJson = shopService.post(FINDER_LIST_URL, param);
+    return ResponseUtils.decode(resJson, FinderListResponse.class);
+  }
+
+  @Override
+  public FinderOverallResponse getFinderOverall(String ds) throws WxErrorException {
+    CompassFinderBaseParam param = new CompassFinderBaseParam(ds);
+    String resJson = shopService.post(GET_FINDER_OVERALL_URL, param);
+    return ResponseUtils.decode(resJson, FinderOverallResponse.class);
+  }
+
+  @Override
+  public FinderProductListResponse getFinderProductList(String ds, String finderId) throws WxErrorException {
+    CompassFinderIdParam param = new CompassFinderIdParam(ds, finderId);
+    String resJson = shopService.post(GET_FINDER_PRODUCT_LIST_URL, param);
+    return ResponseUtils.decode(resJson, FinderProductListResponse.class);
+  }
+
+  @Override
+  public FinderProductOverallResponse getFinderProductOverall(String ds, String finderId) throws WxErrorException {
+    CompassFinderIdParam param = new CompassFinderIdParam(ds, finderId);
+    String resJson = shopService.post(GET_FINDER_PRODUCT_OVERALL_URL, param);
+    return ResponseUtils.decode(resJson, FinderProductOverallResponse.class);
+  }
+
+  @Override
+  public ShopLiveListResponse getShopLiveList(String ds, String finderId) throws WxErrorException {
+    CompassFinderIdParam param = new CompassFinderIdParam(ds, finderId);
+    String resJson = shopService.post(GET_LIVE_LIST_URL, param);
+    return ResponseUtils.decode(resJson, ShopLiveListResponse.class);
+  }
+
+  @Override
+  public ShopProductDataResponse getShopProductData(String ds, String productId) throws WxErrorException {
+    ShopProductDataParam param = new ShopProductDataParam(ds, productId);
+    String resJson = shopService.post(GET_SHOP_PRODUCT_DATA_URL, param);
+    return ResponseUtils.decode(resJson, ShopProductDataResponse.class);
+  }
+
+  @Override
+  public ShopProductListResponse getShopProductList(String ds) throws WxErrorException {
+    CompassFinderBaseParam param = new CompassFinderBaseParam(ds);
+    String resJson = shopService.post(GET_SHOP_PRODUCT_LIST_URL, param);
+    return ResponseUtils.decode(resJson, ShopProductListResponse.class);
+  }
+
+  @Override
+  public ShopSaleProfileDataResponse getShopSaleProfileData(String ds, Integer type) throws WxErrorException {
+    ShopSaleProfileDataParam param = new ShopSaleProfileDataParam(ds, type);
+    String resJson = shopService.post(GET_SHOP_SALE_PROFILE_DATA_URL, param);
+    return ResponseUtils.decode(resJson, ShopSaleProfileDataResponse.class);
+  }
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelCouponServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelCouponServiceImpl.java
index 174626f4a9..22abf25fb0 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelCouponServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelCouponServiceImpl.java
@@ -35,9 +35,9 @@
 public class WxChannelCouponServiceImpl implements WxChannelCouponService {
 
   /** 微信商店服务 */
-  private final BaseWxChannelServiceImpl shopService;
+  private final BaseWxChannelServiceImpl<?, ?> shopService;
 
-  public WxChannelCouponServiceImpl(BaseWxChannelServiceImpl shopService) {
+  public WxChannelCouponServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
     this.shopService = shopService;
   }
 
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelFreightTemplateServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelFreightTemplateServiceImpl.java
index 8fbfbd09c3..b8f00a4f84 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelFreightTemplateServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelFreightTemplateServiceImpl.java
@@ -24,9 +24,9 @@
 @Slf4j
 public class WxChannelFreightTemplateServiceImpl implements WxChannelFreightTemplateService {
     /** 微信商店服务 */
-    private final BaseWxChannelServiceImpl shopService;
+    private final BaseWxChannelServiceImpl<?, ?> shopService;
 
-    public WxChannelFreightTemplateServiceImpl(BaseWxChannelServiceImpl shopService) {
+    public WxChannelFreightTemplateServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
         this.shopService = shopService;
     }
 
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelFundServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelFundServiceImpl.java
index 050a19f44d..7cf30905ec 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelFundServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelFundServiceImpl.java
@@ -54,9 +54,9 @@ public class WxChannelFundServiceImpl implements WxChannelFundService {
 
 
   /** 微信商店服务 */
-  private final BaseWxChannelServiceImpl shopService;
+  private final BaseWxChannelServiceImpl<?, ?> shopService;
 
-  public WxChannelFundServiceImpl(BaseWxChannelServiceImpl shopService) {
+  public WxChannelFundServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
     this.shopService = shopService;
   }
 
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelLiveDashboardServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelLiveDashboardServiceImpl.java
index 7c9c876e9b..7eace4377b 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelLiveDashboardServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelLiveDashboardServiceImpl.java
@@ -27,10 +27,10 @@ public class WxChannelLiveDashboardServiceImpl implements WxChannelLiveDashboard
   /**
    * 微信商店服务
    */
-  private final BaseWxChannelServiceImpl shopService;
+  private final BaseWxChannelServiceImpl<?, ?> shopService;
   private final ObjectMapper objectMapper = new ObjectMapper();
 
-  public WxChannelLiveDashboardServiceImpl(BaseWxChannelServiceImpl shopService) {this.shopService = shopService;}
+  public WxChannelLiveDashboardServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {this.shopService = shopService;}
 
   @Override
   public LiveListResponse getLiveList(Long ds) throws WxErrorException {
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelOrderServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelOrderServiceImpl.java
index 65eec5dd29..fd26268333 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelOrderServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelOrderServiceImpl.java
@@ -1,8 +1,20 @@
 package me.chanjar.weixin.channel.api.impl;
 
 import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Delivery.DELIVERY_SEND_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Delivery.GET_DELIVERY_COMPANY_NEW_URL;
 import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Delivery.GET_DELIVERY_COMPANY_URL;
-import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Order.*;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Order.ACCEPT_ADDRESS_MODIFY_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Order.DECODE_SENSITIVE_INFO_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Order.ORDER_GET_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Order.ORDER_LIST_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Order.ORDER_SEARCH_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Order.REJECT_ADDRESS_MODIFY_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Order.UPDATE_ADDRESS_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Order.UPDATE_EXPRESS_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Order.UPDATE_PRICE_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Order.UPDATE_REMARK_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Order.UPLOAD_FRESH_INSPECT_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Order.VIRTUAL_TEL_NUMBER_URL;
 
 import java.util.List;
 import lombok.extern.slf4j.Slf4j;
@@ -12,16 +24,21 @@
 import me.chanjar.weixin.channel.bean.delivery.DeliveryCompanyResponse;
 import me.chanjar.weixin.channel.bean.delivery.DeliveryInfo;
 import me.chanjar.weixin.channel.bean.delivery.DeliverySendParam;
+import me.chanjar.weixin.channel.bean.delivery.FreshInspectParam;
+import me.chanjar.weixin.channel.bean.delivery.PackageAuditInfo;
 import me.chanjar.weixin.channel.bean.order.ChangeOrderInfo;
+import me.chanjar.weixin.channel.bean.order.DecodeSensitiveInfoResponse;
 import me.chanjar.weixin.channel.bean.order.DeliveryUpdateParam;
 import me.chanjar.weixin.channel.bean.order.OrderAddressParam;
 import me.chanjar.weixin.channel.bean.order.OrderIdParam;
+import me.chanjar.weixin.channel.bean.order.OrderInfoParam;
 import me.chanjar.weixin.channel.bean.order.OrderInfoResponse;
 import me.chanjar.weixin.channel.bean.order.OrderListParam;
 import me.chanjar.weixin.channel.bean.order.OrderListResponse;
 import me.chanjar.weixin.channel.bean.order.OrderPriceParam;
 import me.chanjar.weixin.channel.bean.order.OrderRemarkParam;
 import me.chanjar.weixin.channel.bean.order.OrderSearchParam;
+import me.chanjar.weixin.channel.bean.order.VirtualTelNumberResponse;
 import me.chanjar.weixin.channel.util.ResponseUtils;
 import me.chanjar.weixin.common.error.WxErrorException;
 
@@ -35,15 +52,22 @@
 public class WxChannelOrderServiceImpl implements WxChannelOrderService {
 
   /** 微信商店服务 */
-  private final BaseWxChannelServiceImpl shopService;
+  private final BaseWxChannelServiceImpl<?, ?> shopService;
 
-  public WxChannelOrderServiceImpl(BaseWxChannelServiceImpl shopService) {
+  public WxChannelOrderServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
     this.shopService = shopService;
   }
 
   @Override
   public OrderInfoResponse getOrder(String orderId) throws WxErrorException {
-    OrderIdParam param = new OrderIdParam(orderId);
+    OrderInfoParam param = new OrderInfoParam(orderId, null);
+    String resJson = shopService.post(ORDER_GET_URL, param);
+    return ResponseUtils.decode(resJson, OrderInfoResponse.class);
+  }
+
+  @Override
+  public OrderInfoResponse getOrder(String orderId, Boolean encodeSensitiveInfo) throws WxErrorException {
+    OrderInfoParam param = new OrderInfoParam(orderId, encodeSensitiveInfo);
     String resJson = shopService.post(ORDER_GET_URL, param);
     return ResponseUtils.decode(resJson, OrderInfoResponse.class);
   }
@@ -115,6 +139,16 @@ public DeliveryCompanyResponse listDeliveryCompany() throws WxErrorException {
     return ResponseUtils.decode(resJson, DeliveryCompanyResponse.class);
   }
 
+  @Override
+  public DeliveryCompanyResponse listDeliveryCompany(Boolean ewaybillOnly) throws WxErrorException {
+    String reqJson = "{}";
+    if (ewaybillOnly != null) {
+      reqJson = "{\"ewaybill_only\":" + ewaybillOnly + "}";
+    }
+    String resJson = shopService.post(GET_DELIVERY_COMPANY_NEW_URL, reqJson);
+    return ResponseUtils.decode(resJson, DeliveryCompanyResponse.class);
+  }
+
   @Override
   public WxChannelBaseResponse deliveryOrder(String orderId, List<DeliveryInfo> deliveryList)
     throws WxErrorException {
@@ -122,4 +156,26 @@ public WxChannelBaseResponse deliveryOrder(String orderId, List<DeliveryInfo> de
     String resJson = shopService.post(DELIVERY_SEND_URL, param);
     return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
   }
+
+  @Override
+  public WxChannelBaseResponse uploadFreshInspect(String orderId, List<PackageAuditInfo> items)
+    throws WxErrorException {
+    FreshInspectParam param = new FreshInspectParam(orderId, items);
+    String resJson = shopService.post(UPLOAD_FRESH_INSPECT_URL, param);
+    return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
+  }
+
+  @Override
+  public VirtualTelNumberResponse getVirtualTelNumber(String orderId) throws WxErrorException {
+    String reqJson = "{\"order_id\":\"" + orderId + "\"}";
+    String resJson = shopService.post(VIRTUAL_TEL_NUMBER_URL, reqJson);
+    return ResponseUtils.decode(resJson, VirtualTelNumberResponse.class);
+  }
+
+  @Override
+  public DecodeSensitiveInfoResponse decodeSensitiveInfo(String orderId) throws WxErrorException {
+    String reqJson = "{\"order_id\":\"" + orderId + "\"}";
+    String resJson = shopService.post(DECODE_SENSITIVE_INFO_URL, reqJson);
+    return ResponseUtils.decode(resJson, DecodeSensitiveInfoResponse.class);
+  }
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelProductServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelProductServiceImpl.java
index eb168a09e3..08c9638f0c 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelProductServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelProductServiceImpl.java
@@ -6,16 +6,22 @@
 import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.DELETE_LIMIT_TASK_URL;
 import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.LIST_LIMIT_TASK_URL;
 import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_ADD_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_AUDIT_FREE_UPDATE_URL;
 import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_DELISTING_URL;
 import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_DEL_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_GET_STOCK_BATCH_URL;
 import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_GET_STOCK_URL;
 import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_GET_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_H5URL_URL;
 import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_LISTING_URL;
 import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_LIST_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_QRCODE_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_TAGLINK_URL;
 import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_UPDATE_STOCK_URL;
 import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.SPU_UPDATE_URL;
 import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Spu.STOP_LIMIT_TASK_URL;
 
+import java.util.List;
 import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.channel.api.WxChannelProductService;
 import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
@@ -23,13 +29,20 @@
 import me.chanjar.weixin.channel.bean.limit.LimitTaskListParam;
 import me.chanjar.weixin.channel.bean.limit.LimitTaskListResponse;
 import me.chanjar.weixin.channel.bean.limit.LimitTaskParam;
+import me.chanjar.weixin.channel.bean.product.SkuStockBatchParam;
+import me.chanjar.weixin.channel.bean.product.SkuStockBatchResponse;
 import me.chanjar.weixin.channel.bean.product.SkuStockParam;
 import me.chanjar.weixin.channel.bean.product.SkuStockResponse;
+import me.chanjar.weixin.channel.bean.product.SpuFastInfo;
 import me.chanjar.weixin.channel.bean.product.SpuGetResponse;
 import me.chanjar.weixin.channel.bean.product.SpuInfo;
 import me.chanjar.weixin.channel.bean.product.SpuListParam;
 import me.chanjar.weixin.channel.bean.product.SpuListResponse;
+import me.chanjar.weixin.channel.bean.product.SpuUpdateInfo;
 import me.chanjar.weixin.channel.bean.product.SpuUpdateResponse;
+import me.chanjar.weixin.channel.bean.product.link.ProductH5UrlResponse;
+import me.chanjar.weixin.channel.bean.product.link.ProductQrCodeResponse;
+import me.chanjar.weixin.channel.bean.product.link.ProductTagLinkResponse;
 import me.chanjar.weixin.channel.util.JsonUtils;
 import me.chanjar.weixin.channel.util.ResponseUtils;
 import me.chanjar.weixin.common.error.WxErrorException;
@@ -43,12 +56,26 @@
 public class WxChannelProductServiceImpl implements WxChannelProductService {
 
   /** 微信商店服务 */
-  private final BaseWxChannelServiceImpl shopService;
+  private final BaseWxChannelServiceImpl<?, ?> shopService;
 
-  public WxChannelProductServiceImpl(BaseWxChannelServiceImpl shopService) {
+  public WxChannelProductServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
     this.shopService = shopService;
   }
 
+  @Override
+  public SpuUpdateResponse addProduct(SpuUpdateInfo info) throws WxErrorException {
+    String reqJson = JsonUtils.encode(info);
+    String resJson = shopService.post(SPU_ADD_URL, reqJson);
+    return ResponseUtils.decode(resJson, SpuUpdateResponse.class);
+  }
+
+  @Override
+  public SpuUpdateResponse updateProduct(SpuUpdateInfo info) throws WxErrorException {
+    String reqJson = JsonUtils.encode(info);
+    String resJson = shopService.post(SPU_UPDATE_URL, reqJson);
+    return ResponseUtils.decode(resJson, SpuUpdateResponse.class);
+  }
+
   @Override
   public SpuUpdateResponse addProduct(SpuInfo info) throws WxErrorException {
     String reqJson = JsonUtils.encode(info);
@@ -63,6 +90,13 @@ public SpuUpdateResponse updateProduct(SpuInfo info) throws WxErrorException {
     return ResponseUtils.decode(resJson, SpuUpdateResponse.class);
   }
 
+  @Override
+  public WxChannelBaseResponse updateProductAuditFree(SpuFastInfo info) throws WxErrorException {
+    String reqJson = JsonUtils.encode(info);
+    String resJson = shopService.post(SPU_AUDIT_FREE_UPDATE_URL, reqJson);
+    return ResponseUtils.decode(resJson, SpuUpdateResponse.class);
+  }
+
   @Override
   public WxChannelBaseResponse updateStock(String productId, String skuId, Integer diffType, Integer num)
     throws WxErrorException {
@@ -148,6 +182,35 @@ public SkuStockResponse getSkuStock(String productId, String skuId) throws WxErr
     return ResponseUtils.decode(resJson, SkuStockResponse.class);
   }
 
+  @Override
+  public SkuStockBatchResponse getSkuStockBatch(List<String> productIds) throws WxErrorException {
+    SkuStockBatchParam param = new SkuStockBatchParam(productIds);
+    String reqJson = JsonUtils.encode(param);
+    String resJson = shopService.post(SPU_GET_STOCK_BATCH_URL, reqJson);
+    return ResponseUtils.decode(resJson, SkuStockBatchResponse.class);
+  }
+
+  @Override
+  public ProductH5UrlResponse getProductH5Url(String productId) throws WxErrorException {
+    String reqJson = "{\"product_id\":\"" + productId + "\"}";
+    String resJson = shopService.post(SPU_H5URL_URL, reqJson);
+    return ResponseUtils.decode(resJson, ProductH5UrlResponse.class);
+  }
+
+  @Override
+  public ProductQrCodeResponse getProductQrCode(String productId) throws WxErrorException {
+    String reqJson = "{\"product_id\":\"" + productId + "\"}";
+    String resJson = shopService.post(SPU_QRCODE_URL, reqJson);
+    return ResponseUtils.decode(resJson, ProductQrCodeResponse.class);
+  }
+
+  @Override
+  public ProductTagLinkResponse getProductTagLink(String productId) throws WxErrorException {
+    String reqJson = "{\"product_id\":\"" + productId + "\"}";
+    String resJson = shopService.post(SPU_TAGLINK_URL, reqJson);
+    return ResponseUtils.decode(resJson, ProductTagLinkResponse.class);
+  }
+
   @Override
   public LimitTaskAddResponse addLimitTask(LimitTaskParam param) throws WxErrorException {
     String reqJson = JsonUtils.encode(param);
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelServiceHttpClientImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelServiceHttpClientImpl.java
index e0cb767619..6f380f80fb 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelServiceHttpClientImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelServiceHttpClientImpl.java
@@ -1,30 +1,28 @@
 package me.chanjar.weixin.channel.api.impl;
 
-import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.GET_ACCESS_TOKEN_URL;
-import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.GET_STABLE_ACCESS_TOKEN_URL;
-
-import java.io.IOException;
 import lombok.extern.slf4j.Slf4j;
-import me.chanjar.weixin.channel.api.WxChannelVipService;
-import me.chanjar.weixin.channel.bean.token.StableToken;
+import me.chanjar.weixin.channel.bean.token.StableTokenParam;
 import me.chanjar.weixin.channel.config.WxChannelConfig;
 import me.chanjar.weixin.channel.util.JsonUtils;
-import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
+import me.chanjar.weixin.common.util.http.apache.ApacheBasicResponseHandler;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
 import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.http.Consts;
 import org.apache.http.HttpHost;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
 import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.BasicResponseHandler;
 import org.apache.http.impl.client.CloseableHttpClient;
 
+import java.io.IOException;
+
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.GET_ACCESS_TOKEN_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.GET_STABLE_ACCESS_TOKEN_URL;
+
 /**
  * @author <a href="https://github.com/lixize">Zeyes</a>
  */
@@ -33,19 +31,6 @@ public class WxChannelServiceHttpClientImpl extends BaseWxChannelServiceImpl<Htt
 
   private CloseableHttpClient httpClient;
   private HttpHost httpProxy;
-  private Boolean stabled = false;
-  private Boolean forceRefresh = false;
-
-  /**
-   * 设置调用接口参数.
-   *
-   * @param stabled      false 表示调用AccessToken接口， true调用稳定版接口
-   * @param forceRefresh stabled=true使用， true表示强制刷新模式
-   */
-  public WxChannelServiceHttpClientImpl(Boolean stabled, Boolean forceRefresh) {
-    this.stabled = stabled;
-    this.forceRefresh = forceRefresh;
-  }
 
   @Override
   public void initHttp() {
@@ -78,31 +63,12 @@ public HttpHost getRequestHttpProxy() {
   }
 
   @Override
-  public HttpType getRequestType() {
-    return HttpType.APACHE_HTTP;
+  public HttpClientType getRequestType() {
+    return HttpClientType.APACHE_HTTP;
   }
 
   @Override
-  protected String doGetAccessTokenRequest() throws WxErrorException {
-    try {
-      if (stabled) {
-        return internalGetStableAccessToken(this.forceRefresh);
-      } else{
-        return  internalGetAccessToken();
-      }
-    } catch(Exception e) {
-      throw new WxErrorException(e);
-    }
-
-  }
-
-  /**
-   * 获取access_token
-   *
-   * @return 返回json的字符串
-   * @throws IOException the io exception
-   */
-  protected String internalGetAccessToken() throws IOException {
+  protected String doGetAccessTokenRequest() throws IOException {
     WxChannelConfig config = this.getConfig();
     String url = StringUtils.isNotEmpty(config.getAccessTokenUrl()) ? config.getAccessTokenUrl() :
       StringUtils.isNotEmpty(config.getApiHostUrl()) ?
@@ -110,30 +76,14 @@ protected String internalGetAccessToken() throws IOException {
 
     url = String.format(url, config.getAppid(), config.getSecret());
 
-    HttpGet httpGet = null;
-    CloseableHttpResponse response = null;
-    try {
-      httpGet = new HttpGet(url);
-      if (this.getRequestHttpProxy() != null) {
-        RequestConfig requestConfig = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
-        httpGet.setConfig(requestConfig);
-      }
-      response = getRequestHttpClient().execute(httpGet);
-      return new BasicResponseHandler().handleResponse(response);
-    } finally {
-      if (httpGet != null) {
-        httpGet.releaseConnection();
-      }
-      if (response != null) {
-        try {
-          response.close();
-        } catch (IOException ignored) {
-        }
-      }
+    HttpGet httpGet = new HttpGet(url);
+    if (this.getRequestHttpProxy() != null) {
+      RequestConfig requestConfig = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
+      httpGet.setConfig(requestConfig);
     }
+    return getRequestHttpClient().execute(httpGet, ApacheBasicResponseHandler.INSTANCE);
   }
 
-
   /**
    * 获取稳定版接口调用凭据
    *
@@ -141,7 +91,8 @@ protected String internalGetAccessToken() throws IOException {
    * @return 返回json的字符串
    * @throws IOException the io exception
    */
-  protected String internalGetStableAccessToken(Boolean forceRefresh) throws IOException {
+  @Override
+  protected String doGetStableAccessTokenRequest(boolean forceRefresh) throws IOException {
     WxChannelConfig config = this.getConfig();
     String url = GET_STABLE_ACCESS_TOKEN_URL;
 
@@ -150,19 +101,15 @@ protected String internalGetStableAccessToken(Boolean forceRefresh) throws IOExc
       RequestConfig requestConfig = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
       httpPost.setConfig(requestConfig);
     }
-
-    StableToken stableToken = new StableToken("client_credential", config.getAppid(),config.getSecret(), forceRefresh);
-
-    StringEntity entity = new StringEntity(JsonUtils.encode(stableToken), Consts.UTF_8);
-    entity.setContentType("application/json; charset=utf-8");
-    httpPost.setEntity(entity);
-
-    try (CloseableHttpResponse response = getRequestHttpClient().execute(httpPost)) {
-      return new BasicResponseHandler().handleResponse(response);
-    } finally {
-      httpPost.releaseConnection();
-    }
+    StableTokenParam requestParam = new StableTokenParam();
+    requestParam.setAppId(config.getAppid());
+    requestParam.setSecret(config.getSecret());
+    requestParam.setGrantType("client_credential");
+    requestParam.setForceRefresh(forceRefresh);
+    String requestJson = JsonUtils.encode(requestParam);
+    assert requestJson != null;
+
+    httpPost.setEntity(new StringEntity(requestJson, ContentType.APPLICATION_JSON));
+    return getRequestHttpClient().execute(httpPost, ApacheBasicResponseHandler.INSTANCE);
   }
-
-
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelServiceHttpComponentsImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelServiceHttpComponentsImpl.java
new file mode 100644
index 0000000000..6cf2d38503
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelServiceHttpComponentsImpl.java
@@ -0,0 +1,113 @@
+package me.chanjar.weixin.channel.api.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.channel.bean.token.StableTokenParam;
+import me.chanjar.weixin.channel.config.WxChannelConfig;
+import me.chanjar.weixin.channel.util.JsonUtils;
+import me.chanjar.weixin.common.util.http.HttpClientType;
+import me.chanjar.weixin.common.util.http.apache.ApacheBasicResponseHandler;
+import me.chanjar.weixin.common.util.http.hc.BasicResponseHandler;
+import me.chanjar.weixin.common.util.http.hc.DefaultHttpComponentsClientBuilder;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsClientBuilder;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hc.client5.http.classic.HttpClient;
+import org.apache.hc.client5.http.classic.methods.HttpGet;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+
+import java.io.IOException;
+
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.GET_ACCESS_TOKEN_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.GET_STABLE_ACCESS_TOKEN_URL;
+
+/**
+ * @author altusea
+ */
+@Slf4j
+public class WxChannelServiceHttpComponentsImpl extends BaseWxChannelServiceImpl<HttpClient, HttpHost> {
+
+  private CloseableHttpClient httpClient;
+  private HttpHost httpProxy;
+
+  @Override
+  public void initHttp() {
+    WxChannelConfig config = this.getConfig();
+    HttpComponentsClientBuilder apacheHttpClientBuilder = DefaultHttpComponentsClientBuilder.get();
+
+    apacheHttpClientBuilder.httpProxyHost(config.getHttpProxyHost())
+      .httpProxyPort(config.getHttpProxyPort())
+      .httpProxyUsername(config.getHttpProxyUsername())
+      .httpProxyPassword(config.getHttpProxyPassword().toCharArray());
+
+    if (config.getHttpProxyHost() != null && config.getHttpProxyPort() > 0) {
+      this.httpProxy = new HttpHost(config.getHttpProxyHost(), config.getHttpProxyPort());
+    }
+
+    this.httpClient = apacheHttpClientBuilder.build();
+  }
+
+  @Override
+  public CloseableHttpClient getRequestHttpClient() {
+    return httpClient;
+  }
+
+  @Override
+  public HttpHost getRequestHttpProxy() {
+    return httpProxy;
+  }
+
+  @Override
+  public HttpClientType getRequestType() {
+    return HttpClientType.HTTP_COMPONENTS;
+  }
+
+  @Override
+  protected String doGetAccessTokenRequest() throws IOException {
+    WxChannelConfig config = this.getConfig();
+    String url = StringUtils.isNotEmpty(config.getAccessTokenUrl()) ? config.getAccessTokenUrl() :
+      StringUtils.isNotEmpty(config.getApiHostUrl()) ?
+        GET_ACCESS_TOKEN_URL.replace("https://api.weixin.qq.com", config.getApiHostUrl()) : GET_ACCESS_TOKEN_URL;
+
+    url = String.format(url, config.getAppid(), config.getSecret());
+
+    HttpGet httpGet = new HttpGet(url);
+    if (this.getRequestHttpProxy() != null) {
+      RequestConfig requestConfig = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
+      httpGet.setConfig(requestConfig);
+    }
+    return getRequestHttpClient().execute(httpGet, BasicResponseHandler.INSTANCE);
+  }
+
+  /**
+   * 获取稳定版接口调用凭据
+   *
+   * @param forceRefresh false 为普通模式， true为强制刷新模式
+   * @return 返回json的字符串
+   * @throws IOException the io exception
+   */
+  @Override
+  protected String doGetStableAccessTokenRequest(boolean forceRefresh) throws IOException {
+    WxChannelConfig config = this.getConfig();
+    String url = GET_STABLE_ACCESS_TOKEN_URL;
+
+    HttpPost httpPost = new HttpPost(url);
+    if (this.getRequestHttpProxy() != null) {
+      RequestConfig requestConfig = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
+      httpPost.setConfig(requestConfig);
+    }
+    StableTokenParam requestParam = new StableTokenParam();
+    requestParam.setAppId(config.getAppid());
+    requestParam.setSecret(config.getSecret());
+    requestParam.setGrantType("client_credential");
+    requestParam.setForceRefresh(forceRefresh);
+    String requestJson = JsonUtils.encode(requestParam);
+    assert requestJson != null;
+
+    httpPost.setEntity(new StringEntity(requestJson, ContentType.APPLICATION_JSON));
+    return getRequestHttpClient().execute(httpPost, BasicResponseHandler.INSTANCE);
+  }
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelServiceImpl.java
index 1929d9baec..6f2c349f3f 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelServiceImpl.java
@@ -10,20 +10,17 @@
 @Slf4j
 public class WxChannelServiceImpl extends WxChannelServiceHttpClientImpl {
 
-  /**
-   * 设置普通模式access_token接口参数
-   */
   public WxChannelServiceImpl() {
-    super(false, false);
   }
 
-  /**
-   * 设置获取access_token接口参数.
-   *
-   * @param stabled      false 表示调用普通模式AccessToken接口， true调用稳定模式接口
-   * @param forceRefresh stabled=true使用， true表示强制刷新模式
-   */
-  public WxChannelServiceImpl(Boolean stabled, Boolean forceRefresh) {
-    super(stabled, forceRefresh);
-  }
+//  /**
+//   * 设置获取access_token接口参数.
+//   *
+//   * @param stabled      false 表示调用普通模式AccessToken接口， true调用稳定模式接口
+//   * @param forceRefresh stabled=true使用， true表示强制刷新模式
+//   * @deprecated 请使用 {@link BaseWxChannelServiceImpl#setConfig(WxChannelConfig) } 替代
+//   */
+//  @Deprecated
+//  public WxChannelServiceImpl(Boolean stabled, Boolean forceRefresh) {
+//  }
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelServiceOkHttpImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelServiceOkHttpImpl.java
index df467d6988..6d109be70d 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelServiceOkHttpImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelServiceOkHttpImpl.java
@@ -1,24 +1,26 @@
 package me.chanjar.weixin.channel.api.impl;
 
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.GET_ACCESS_TOKEN_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.GET_STABLE_ACCESS_TOKEN_URL;
+
+import java.io.IOException;
+import java.util.Objects;
 import lombok.extern.slf4j.Slf4j;
-import me.chanjar.weixin.channel.bean.token.StableToken;
+import me.chanjar.weixin.channel.bean.token.StableTokenParam;
+import me.chanjar.weixin.channel.config.WxChannelConfig;
 import me.chanjar.weixin.channel.util.JsonUtils;
-import me.chanjar.weixin.common.bean.WxAccessToken;
-import me.chanjar.weixin.common.enums.WxType;
-import me.chanjar.weixin.common.error.WxError;
-import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
 import me.chanjar.weixin.common.util.http.okhttp.DefaultOkHttpClientBuilder;
 import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
-import okhttp3.*;
+import okhttp3.Authenticator;
+import okhttp3.Credentials;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import okhttp3.Route;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.http.Consts;
-import org.apache.http.entity.StringEntity;
-
-import java.io.IOException;
-
-import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.GET_ACCESS_TOKEN_URL;
-import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.GET_STABLE_ACCESS_TOKEN_URL;
 
 /**
  * @author : zhenyun.su
@@ -28,19 +30,8 @@
 public class WxChannelServiceOkHttpImpl extends BaseWxChannelServiceImpl<OkHttpClient, OkHttpProxyInfo> {
   private OkHttpClient httpClient;
   private OkHttpProxyInfo httpProxy;
-  private Boolean stabled = false;
-  private Boolean forceRefresh = false;
-  protected final Object globalAccessTokenRefreshLock = new Object();
 
-  /**
-   * 设置调用接口参数.
-   *
-   * @param stabled      false 表示调用AccessToken接口， true调用稳定版接口
-   * @param forceRefresh stabled=true使用， true表示强制刷新模式
-   */
-  public WxChannelServiceOkHttpImpl(Boolean stabled, Boolean forceRefresh) {
-    this.stabled = stabled;
-    this.forceRefresh = forceRefresh;
+  public WxChannelServiceOkHttpImpl() {
   }
 
   @Override
@@ -74,81 +65,45 @@ public OkHttpProxyInfo getRequestHttpProxy() {
   }
 
   @Override
-  public HttpType getRequestType() {
-    return HttpType.OK_HTTP;
+  public HttpClientType getRequestType() {
+    return HttpClientType.OK_HTTP;
   }
 
   @Override
-  protected String doGetAccessTokenRequest() throws WxErrorException {
-    if (stabled) {
-      return internalGetStableAccessToken(this.forceRefresh);
-    } else{
-      return internalGetAccessToken(forceRefresh);
-    }
-  }
-
-  public String internalGetStableAccessToken(boolean forceRefresh) throws WxErrorException {
-    if (!this.config.isAccessTokenExpired() && !forceRefresh) {
-      return this.config.getAccessToken();
-    } else {
-      synchronized(this.globalAccessTokenRefreshLock) {
-        OkHttpClient client = this.getRequestHttpClient();
-
-        String url = String.format(GET_STABLE_ACCESS_TOKEN_URL, config.getAppid(), config.getSecret());
+  protected String doGetAccessTokenRequest() throws IOException {
+    WxChannelConfig config = this.getConfig();
+    String url = StringUtils.isNotEmpty(config.getAccessTokenUrl()) ? config.getAccessTokenUrl() :
+      StringUtils.isNotEmpty(config.getApiHostUrl()) ?
+        GET_ACCESS_TOKEN_URL.replace("https://api.weixin.qq.com", config.getApiHostUrl()) : GET_ACCESS_TOKEN_URL;
 
-        StableToken stableToken = new StableToken("client_credential", config.getAppid(),config.getSecret(), forceRefresh);
+    url = String.format(url, config.getAppid(), config.getSecret());
 
-        RequestBody body = RequestBody.Companion.create(JsonUtils.encode(stableToken), MediaType.parse("application/json; charset=utf-8"));
-
-        Request request = (new Request.Builder()).url(url).post(body).build();
-        String resultContent = null;
-        try {
-          Response response = client.newCall(request).execute();
-          resultContent = response.body().string();
-        } catch (IOException var9) {
-          log.error(var9.getMessage(), var9);
-        }
-
-        WxError error = WxError.fromJson(resultContent, WxType.CP);
-        if (error.getErrorCode() != 0) {
-          throw new WxErrorException(error);
-        }
-
-        WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
-        this.config.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
-      }
-      return this.config.getAccessToken();
+    Request request = new Request.Builder().url(url).get().build();
+    try (Response response = getRequestHttpClient().newCall(request).execute()) {
+      return Objects.requireNonNull(response.body()).string();
     }
   }
 
-  public String internalGetAccessToken(boolean forceRefresh) throws WxErrorException {
-    if (!this.config.isAccessTokenExpired() && !forceRefresh) {
-      return this.config.getAccessToken();
-    } else {
-      synchronized(this.globalAccessTokenRefreshLock) {
-        OkHttpClient client = this.getRequestHttpClient();
-
-        String url = String.format(GET_ACCESS_TOKEN_URL, config.getAppid(), config.getSecret());
-
-        Request request = (new Request.Builder()).url(url).get().build();
-
-        String resultContent = null;
-        try {
-          Response response = client.newCall(request).execute();
-          resultContent = response.body().string();
-        } catch (IOException var9) {
-          log.error(var9.getMessage(), var9);
-        }
-
-        WxError error = WxError.fromJson(resultContent, WxType.CP);
-        if (error.getErrorCode() != 0) {
-          throw new WxErrorException(error);
-        }
-
-        WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
-        this.config.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
-      }
-      return this.config.getAccessToken();
+  @Override
+  protected String doGetStableAccessTokenRequest(boolean forceRefresh) throws IOException {
+    WxChannelConfig config = this.getConfig();
+    String url = StringUtils.isNotEmpty(config.getAccessTokenUrl()) ?
+      config.getAccessTokenUrl() : StringUtils.isNotEmpty(config.getApiHostUrl()) ?
+      GET_STABLE_ACCESS_TOKEN_URL.replace("https://api.weixin.qq.com", config.getApiHostUrl()) :
+      GET_STABLE_ACCESS_TOKEN_URL;
+
+    StableTokenParam requestParam = new StableTokenParam();
+    requestParam.setAppId(config.getAppid());
+    requestParam.setSecret(config.getSecret());
+    requestParam.setGrantType("client_credential");
+    requestParam.setForceRefresh(forceRefresh);
+    String requestJson = JsonUtils.encode(requestParam);
+    assert requestJson != null;
+
+    RequestBody body = RequestBody.Companion.create(requestJson, MediaType.parse("application/json; charset=utf-8"));
+    Request request = new Request.Builder().url(url).post(body).build();
+    try (Response response = getRequestHttpClient().newCall(request).execute()) {
+      return Objects.requireNonNull(response.body()).string();
     }
   }
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelSharerServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelSharerServiceImpl.java
index 676b310288..3e27b124c7 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelSharerServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelSharerServiceImpl.java
@@ -33,9 +33,9 @@
 public class WxChannelSharerServiceImpl implements WxChannelSharerService {
 
   /** 微信商店服务 */
-  private final BaseWxChannelServiceImpl shopService;
+  private final BaseWxChannelServiceImpl<?, ?> shopService;
 
-  public WxChannelSharerServiceImpl(BaseWxChannelServiceImpl shopService) {
+  public WxChannelSharerServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
     this.shopService = shopService;
   }
 
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelVipServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelVipServiceImpl.java
index 1bad47593d..4644989d60 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelVipServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelVipServiceImpl.java
@@ -18,51 +18,51 @@
 
 @Slf4j
 public class WxChannelVipServiceImpl implements WxChannelVipService {
-  private BaseWxChannelServiceImpl vipHttpService;
+  private final BaseWxChannelServiceImpl<?, ?> shopService;
 
-  public WxChannelVipServiceImpl(BaseWxChannelServiceImpl vipHttpService) {
-    this.vipHttpService = vipHttpService;
+  public WxChannelVipServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
+    this.shopService = shopService;
   }
 
   @Override
   public VipInfoResponse getVipInfo(String openId, Boolean needPhoneNumber) throws WxErrorException {
     VipInfoParam param = new VipInfoParam(openId, needPhoneNumber);
-    String respJson = vipHttpService.post(VIP_USER_INFO_URL, param);
+    String respJson = shopService.post(VIP_USER_INFO_URL, param);
     return ResponseUtils.decode(respJson, VipInfoResponse.class);
   }
 
   @Override
-  public VipListResponse getVipList(Boolean needPhoneNumber, Integer pageNum, Integer PageSize) throws WxErrorException {
-    VipListParam param = new VipListParam(needPhoneNumber, pageNum, PageSize);
-    String respJson = vipHttpService.post(VIP_USER_LIST_URL, param);
+  public VipListResponse getVipList(Boolean needPhoneNumber, Integer pageNum, Integer pageSize) throws WxErrorException {
+    VipListParam param = new VipListParam(needPhoneNumber, pageNum, pageSize);
+    String respJson = shopService.post(VIP_USER_LIST_URL, param);
     return ResponseUtils.decode(respJson, VipListResponse.class);
   }
 
   @Override
   public VipScoreResponse getVipScore(String openId) throws WxErrorException {
-    VipParam param = new VipParam(openId);
-    String respJson = vipHttpService.post(VIP_SCORE_URL, param);
+    VipOpenIdParam param = new VipOpenIdParam(openId);
+    String respJson = shopService.post(VIP_SCORE_URL, param);
     return ResponseUtils.decode(respJson, VipScoreResponse.class);
   }
 
   @Override
   public WxChannelBaseResponse increaseVipScore(String openId, String score, String remark, String requestId) throws WxErrorException {
     VipScoreParam param = new VipScoreParam(openId, score, remark, requestId);
-    String respJson = vipHttpService.post(SCORE_INCREASE_URL, param);
+    String respJson = shopService.post(SCORE_INCREASE_URL, param);
     return ResponseUtils.decode(respJson, WxChannelBaseResponse.class);
   }
 
   @Override
   public WxChannelBaseResponse decreaseVipScore(String openId, String score, String remark, String requestId) throws WxErrorException {
     VipScoreParam param = new VipScoreParam(openId, score, remark, requestId);
-    String respJson = vipHttpService.post(SCORE_DECREASE_URL, param);
+    String respJson = shopService.post(SCORE_DECREASE_URL, param);
     return ResponseUtils.decode(respJson, WxChannelBaseResponse.class);
   }
 
   @Override
   public WxChannelBaseResponse updateVipGrade(String openId, Integer score) throws WxErrorException {
     VipGradeParam param = new VipGradeParam(openId, score);
-    String respJson = vipHttpService.post(GRADE_UPDATE_URL, param);
+    String respJson = shopService.post(GRADE_UPDATE_URL, param);
     return ResponseUtils.decode(respJson, WxChannelBaseResponse.class);
   }
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelWarehouseServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelWarehouseServiceImpl.java
index b9609e5c6b..6805f26a4f 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelWarehouseServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxChannelWarehouseServiceImpl.java
@@ -40,9 +40,9 @@
 public class WxChannelWarehouseServiceImpl implements WxChannelWarehouseService {
 
   /** 微信商店服务 */
-  private final BaseWxChannelServiceImpl shopService;
+  private final BaseWxChannelServiceImpl<?, ?> shopService;
 
-  public WxChannelWarehouseServiceImpl(BaseWxChannelServiceImpl shopService) {
+  public WxChannelWarehouseServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
     this.shopService = shopService;
   }
 
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxFinderLiveServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxFinderLiveServiceImpl.java
index aecd1cccac..51623609cf 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxFinderLiveServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxFinderLiveServiceImpl.java
@@ -26,7 +26,7 @@
 public class WxFinderLiveServiceImpl implements WxFinderLiveService {
 
   /** 微信商店服务 */
-  private final BaseWxChannelServiceImpl shopService;
+  private final BaseWxChannelServiceImpl<?, ?> shopService;
   @Override
   public FinderAttrResponse getFinderAttrByAppid() throws WxErrorException {
     String resJson = shopService.post(GET_FINDER_ATTR_BY_APPID, "{}");
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxLeadComponentServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxLeadComponentServiceImpl.java
index b99cfe9f47..eb1bcee28c 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxLeadComponentServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxLeadComponentServiceImpl.java
@@ -38,7 +38,7 @@
 public class WxLeadComponentServiceImpl implements WxLeadComponentService {
 
   /** 微信商店服务 */
-  private final BaseWxChannelServiceImpl shopService;
+  private final BaseWxChannelServiceImpl<?, ?> shopService;
   private final ObjectMapper objectMapper = new ObjectMapper();
   @Override
   public LeadInfoResponse getLeadsInfoByComponentId(GetLeadInfoByComponentRequest req) throws WxErrorException {
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxLeagueProductServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxLeagueProductServiceImpl.java
index 29620874e2..fc8d2fbadc 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxLeagueProductServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxLeagueProductServiceImpl.java
@@ -32,9 +32,9 @@
 public class WxLeagueProductServiceImpl implements WxLeagueProductService {
 
   /** 微信商店服务 */
-  private final BaseWxChannelServiceImpl shopService;
+  private final BaseWxChannelServiceImpl<?, ?> shopService;
 
-  public WxLeagueProductServiceImpl(BaseWxChannelServiceImpl shopService) {
+  public WxLeagueProductServiceImpl(BaseWxChannelServiceImpl<?, ?>shopService) {
     this.shopService = shopService;
   }
 
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxLeaguePromoterServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxLeaguePromoterServiceImpl.java
index a6bfddfbef..c81df29533 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxLeaguePromoterServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxLeaguePromoterServiceImpl.java
@@ -24,9 +24,9 @@
 public class WxLeaguePromoterServiceImpl implements WxLeaguePromoterService {
 
   /** 微信商店服务 */
-  private final BaseWxChannelServiceImpl shopService;
+  private final BaseWxChannelServiceImpl<?, ?> shopService;
 
-  public WxLeaguePromoterServiceImpl(BaseWxChannelServiceImpl shopService) {
+  public WxLeaguePromoterServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
     this.shopService = shopService;
   }
 
@@ -58,6 +58,34 @@ public PromoterInfoResponse getPromoterInfo(String finderId) throws WxErrorExcep
     return ResponseUtils.decode(resJson, PromoterInfoResponse.class);
   }
 
+  @Override
+  public WxChannelBaseResponse addPromoterV2(String promoterId) throws WxErrorException {
+    String reqJson = "{\"promoter_id\":\"" + promoterId + "\"}";
+    String resJson = shopService.post(ADD_PROMOTER_URL, reqJson);
+    return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
+  }
+
+  @Override
+  public WxChannelBaseResponse updatePromoterV2(String promoterId, int type) throws WxErrorException {
+    String reqJson = "{\"promoter_id\":\"" + promoterId + "\",\"type\":" + type + "}";
+    String resJson = shopService.post(EDIT_PROMOTER_URL, reqJson);
+    return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
+  }
+
+  @Override
+  public WxChannelBaseResponse deletePromoterV2(String promoterId) throws WxErrorException {
+    String reqJson = "{\"promoter_id\":\"" + promoterId + "\"}";
+    String resJson = shopService.post(DELETE_PROMOTER_URL, reqJson);
+    return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
+  }
+
+  @Override
+  public PromoterInfoResponse getPromoterInfoV2(String promoterId) throws WxErrorException {
+    String reqJson = "{\"promoter_id\":\"" + promoterId + "\"}";
+    String resJson = shopService.post(GET_PROMOTER_URL, reqJson);
+    return ResponseUtils.decode(resJson, PromoterInfoResponse.class);
+  }
+
   @Override
   public PromoterListResponse listPromoter(Integer pageIndex, Integer pageSize, Integer status)
     throws WxErrorException {
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxLeagueSupplierServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxLeagueSupplierServiceImpl.java
index d69296bd0f..2b280a2f6d 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxLeagueSupplierServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxLeagueSupplierServiceImpl.java
@@ -38,9 +38,9 @@
 public class WxLeagueSupplierServiceImpl implements WxLeagueSupplierService {
 
   /** 微信商店服务 */
-  private final BaseWxChannelServiceImpl shopService;
+  private final BaseWxChannelServiceImpl<?, ?> shopService;
 
-  public WxLeagueSupplierServiceImpl(BaseWxChannelServiceImpl shopService) {
+  public WxLeagueSupplierServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
     this.shopService = shopService;
   }
 
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxLeagueWindowServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxLeagueWindowServiceImpl.java
index a59fc6efa5..a0c21ab4ef 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxLeagueWindowServiceImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxLeagueWindowServiceImpl.java
@@ -29,9 +29,9 @@
 public class WxLeagueWindowServiceImpl implements WxLeagueWindowService {
 
   /** 微信商店服务 */
-  private final BaseWxChannelServiceImpl shopService;
+  private final BaseWxChannelServiceImpl<?, ?> shopService;
 
-  public WxLeagueWindowServiceImpl(BaseWxChannelServiceImpl shopService) {
+  public WxLeagueWindowServiceImpl(BaseWxChannelServiceImpl<?, ?> shopService) {
     this.shopService = shopService;
   }
 
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxStoreCooperationServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxStoreCooperationServiceImpl.java
new file mode 100644
index 0000000000..56dc78e09e
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxStoreCooperationServiceImpl.java
@@ -0,0 +1,68 @@
+package me.chanjar.weixin.channel.api.impl;
+
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Cooperation.CANCEL_COOPERATION_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Cooperation.GENERATE_QRCODE_COOPERATION_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Cooperation.GET_COOPERATION_STATUS_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Cooperation.LIST_COOPERATION_URL;
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Cooperation.UNBIND_COOPERATION_URL;
+
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.channel.api.WxStoreCooperationService;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+import me.chanjar.weixin.channel.bean.cooperation.CooperationListResponse;
+import me.chanjar.weixin.channel.bean.cooperation.CooperationQrCodeResponse;
+import me.chanjar.weixin.channel.bean.cooperation.CooperationSharerParam;
+import me.chanjar.weixin.channel.bean.cooperation.CooperationStatusResponse;
+import me.chanjar.weixin.channel.util.ResponseUtils;
+import me.chanjar.weixin.common.error.WxErrorException;
+
+/**
+ * 微信小店 合作账号相关接口
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Slf4j
+public class WxStoreCooperationServiceImpl implements WxStoreCooperationService {
+
+  /** 微信小店服务 */
+  private final BaseWxChannelServiceImpl<?, ?> storeService;
+
+  public WxStoreCooperationServiceImpl(BaseWxChannelServiceImpl<?, ?> storeService) {
+    this.storeService = storeService;
+  }
+
+  @Override
+  public CooperationListResponse listCooperation(Integer sharerType) throws WxErrorException {
+    String paramJson = "{\"sharer_type\":" + sharerType + "}";
+    String resJson = storeService.post(LIST_COOPERATION_URL, paramJson);
+    return ResponseUtils.decode(resJson, CooperationListResponse.class);
+  }
+
+  @Override
+  public CooperationStatusResponse getCooperationStatus(String sharerId, Integer sharerType) throws WxErrorException {
+    CooperationSharerParam param = new CooperationSharerParam(sharerId, sharerType);
+    String resJson = storeService.post(GET_COOPERATION_STATUS_URL, param);
+    return ResponseUtils.decode(resJson, CooperationStatusResponse.class);
+  }
+
+  @Override
+  public CooperationQrCodeResponse generateQrCode(String sharerId, Integer sharerType) throws WxErrorException {
+    CooperationSharerParam param = new CooperationSharerParam(sharerId, sharerType);
+    String resJson = storeService.post(GENERATE_QRCODE_COOPERATION_URL, param);
+    return ResponseUtils.decode(resJson, CooperationQrCodeResponse.class);
+  }
+
+  @Override
+  public WxChannelBaseResponse cancelInvitation(String sharerId, Integer sharerType) throws WxErrorException {
+    CooperationSharerParam param = new CooperationSharerParam(sharerId, sharerType);
+    String resJson = storeService.post(CANCEL_COOPERATION_URL, param);
+    return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
+  }
+
+  @Override
+  public WxChannelBaseResponse unbind(String sharerId, Integer sharerType) throws WxErrorException {
+    CooperationSharerParam param = new CooperationSharerParam(sharerId, sharerType);
+    String resJson = storeService.post(UNBIND_COOPERATION_URL, param);
+    return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
+  }
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxStoreHomePageServiceImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxStoreHomePageServiceImpl.java
new file mode 100644
index 0000000000..e3e9f06deb
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/api/impl/WxStoreHomePageServiceImpl.java
@@ -0,0 +1,164 @@
+package me.chanjar.weixin.channel.api.impl;
+
+import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.HomePage.*;
+
+
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.channel.api.WxStoreHomePageService;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+import me.chanjar.weixin.channel.bean.home.background.BackgroundApplyResponse;
+import me.chanjar.weixin.channel.bean.home.background.BackgroundGetResponse;
+import me.chanjar.weixin.channel.bean.home.banner.BannerApplyParam;
+import me.chanjar.weixin.channel.bean.home.banner.BannerApplyResponse;
+import me.chanjar.weixin.channel.bean.home.banner.BannerGetResponse;
+import me.chanjar.weixin.channel.bean.home.banner.BannerInfo;
+import me.chanjar.weixin.channel.bean.home.tree.TreeProductEditInfo;
+import me.chanjar.weixin.channel.bean.home.tree.TreeProductEditParam;
+import me.chanjar.weixin.channel.bean.home.tree.TreeProductListInfo;
+import me.chanjar.weixin.channel.bean.home.tree.TreeProductListParam;
+import me.chanjar.weixin.channel.bean.home.tree.TreeProductListResponse;
+import me.chanjar.weixin.channel.bean.home.tree.TreeShowGetResponse;
+import me.chanjar.weixin.channel.bean.home.tree.TreeShowInfo;
+import me.chanjar.weixin.channel.bean.home.tree.TreeShowParam;
+import me.chanjar.weixin.channel.bean.home.tree.TreeShowSetResponse;
+import me.chanjar.weixin.channel.bean.home.window.WindowProductIndexParam;
+import me.chanjar.weixin.channel.bean.home.window.WindowProductListParam;
+import me.chanjar.weixin.channel.bean.home.window.WindowProductSetting;
+import me.chanjar.weixin.channel.bean.home.window.WindowProductSettingResponse;
+import me.chanjar.weixin.channel.util.ResponseUtils;
+import me.chanjar.weixin.common.error.WxErrorException;
+
+/**
+ * 微信小店 主页管理相关接口
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Slf4j
+public class WxStoreHomePageServiceImpl implements WxStoreHomePageService {
+
+  /** 微信小店服务 */
+  private final BaseWxChannelServiceImpl<?, ?> storeService;
+
+  public WxStoreHomePageServiceImpl(BaseWxChannelServiceImpl<?, ?> storeService) {
+    this.storeService = storeService;
+  }
+
+
+  @Override
+  public WxChannelBaseResponse addTreeProduct(TreeProductEditInfo info) throws WxErrorException {
+    TreeProductEditParam param = new TreeProductEditParam(info);
+    String resJson = storeService.post(ADD_TREE_PRODUCT_URL, param);
+    return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
+  }
+
+  @Override
+  public WxChannelBaseResponse delTreeProduct(TreeProductEditInfo info) throws WxErrorException {
+    TreeProductEditParam param = new TreeProductEditParam(info);
+    String resJson = storeService.post(DEL_TREE_PRODUCT_URL, param);
+    return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
+  }
+
+  @Override
+  public TreeProductListResponse getTreeProductList(TreeProductListInfo info) throws WxErrorException {
+    TreeProductListParam param = new TreeProductListParam(info);
+    String resJson = storeService.post(LIST_TREE_PRODUCT_URL, param);
+    return ResponseUtils.decode(resJson, TreeProductListResponse.class);
+  }
+
+  @Override
+  public TreeShowSetResponse setShowTree(TreeShowInfo info) throws WxErrorException {
+    TreeShowParam param = new TreeShowParam(info);
+    String resJson = storeService.post(SET_SHOW_TREE_URL, param);
+    return ResponseUtils.decode(resJson, TreeShowSetResponse.class);
+  }
+
+  @Override
+  public TreeShowGetResponse getShowTree() throws WxErrorException {
+    String resJson = storeService.post(GET_SHOW_TREE_URL, "");
+    return ResponseUtils.decode(resJson, TreeShowGetResponse.class);
+  }
+
+  @Override
+  public WindowProductSettingResponse listWindowProduct(Integer pageSize, String nextKey) throws WxErrorException {
+    WindowProductListParam param = new WindowProductListParam(pageSize, nextKey);
+    String resJson = storeService.post(LIST_WINDOW_PRODUCT_URL, param);
+    return ResponseUtils.decode(resJson, WindowProductSettingResponse.class);
+  }
+
+  @Override
+  public WxChannelBaseResponse reorderWindowProduct(String productId, Integer indexNum) throws WxErrorException {
+    WindowProductIndexParam param = new WindowProductIndexParam(productId, indexNum);
+    String resJson = storeService.post(REORDER_WINDOW_PRODUCT_URL, param);
+    return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
+  }
+
+  @Override
+  public WxChannelBaseResponse hideWindowProduct(String productId, Integer setHide) throws WxErrorException {
+    WindowProductSetting param = new WindowProductSetting();
+    param.setProductId(productId);
+    param.setSetHide(setHide);
+    String resJson = storeService.post(HIDE_WINDOW_PRODUCT_URL, param);
+    return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
+  }
+
+  @Override
+  public WxChannelBaseResponse topWindowProduct(String productId, Integer setTop) throws WxErrorException {
+    WindowProductSetting param = new WindowProductSetting();
+    param.setProductId(productId);
+    param.setSetTop(setTop);
+    String resJson = storeService.post(TOP_WINDOW_PRODUCT_URL, param);
+    return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
+  }
+
+  @Override
+  public BackgroundApplyResponse applyBackground(String imgUrl) throws WxErrorException {
+    String paramJson = "{\"img_url\":\"" + imgUrl + "\"}";
+    String resJson = storeService.post(APPLY_BACKGROUND_URL, paramJson);
+    return ResponseUtils.decode(resJson, BackgroundApplyResponse.class);
+  }
+
+  @Override
+  public BackgroundGetResponse getBackground() throws WxErrorException {
+    String resJson = storeService.post(GET_BACKGROUND_URL, "");
+    return ResponseUtils.decode(resJson, BackgroundGetResponse.class);
+  }
+
+  @Override
+  public WxChannelBaseResponse cancelBackground(Integer applyId) throws WxErrorException {
+    String paramJson = "{\"apply_id\":" + applyId + "}";
+    String resJson = storeService.post(CANCEL_BACKGROUND_URL, paramJson);
+    return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
+  }
+
+  @Override
+  public WxChannelBaseResponse removeBackground() throws WxErrorException {
+    String resJson = storeService.post(REMOVE_BACKGROUND_URL, "");
+    return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
+  }
+
+  @Override
+  public BannerApplyResponse applyBanner(BannerInfo info) throws WxErrorException {
+    BannerApplyParam param = new BannerApplyParam(info);
+    String resJson = storeService.post(APPLY_BANNER_URL, param);
+    return ResponseUtils.decode(resJson, BannerApplyResponse.class);
+  }
+
+  @Override
+  public BannerGetResponse getBanner() throws WxErrorException {
+    String resJson = storeService.post(GET_BANNER_URL, "");
+    return ResponseUtils.decode(resJson, BannerGetResponse.class);
+  }
+
+  @Override
+  public WxChannelBaseResponse cancelBanner(Integer applyId) throws WxErrorException {
+    String paramJson = "{\"apply_id\":" + applyId + "}";
+    String resJson = storeService.post(CANCEL_BANNER_URL, paramJson);
+    return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
+  }
+
+  @Override
+  public WxChannelBaseResponse removeBanner() throws WxErrorException {
+    String resJson = storeService.post(REMOVE_BANNER_URL, "");
+    return ResponseUtils.decode(resJson, WxChannelBaseResponse.class);
+  }
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/after/AfterSaleExchangeDeliveryInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/after/AfterSaleExchangeDeliveryInfo.java
new file mode 100644
index 0000000000..277d9d4d89
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/after/AfterSaleExchangeDeliveryInfo.java
@@ -0,0 +1,35 @@
+package me.chanjar.weixin.channel.bean.after;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.AddressInfo;
+
+/**
+ * 换货类型的发货物流信息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class AfterSaleExchangeDeliveryInfo implements Serializable {
+
+  private static final long serialVersionUID = 3039216368034112038L;
+
+  /** 快递单号 */
+  @JsonProperty("waybill_id")
+  private String waybillId;
+
+  /** 物流公司id */
+  @JsonProperty("delivery_id")
+  private String deliveryId;
+
+  /** 物流公司名称 */
+  @JsonProperty("delivery_name")
+  private String deliveryName;
+
+  /** 地址信息 */
+  @JsonProperty("address_info")
+  private AddressInfo addressInfo;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/after/AfterSaleExchangeProductInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/after/AfterSaleExchangeProductInfo.java
new file mode 100644
index 0000000000..1e862791ea
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/after/AfterSaleExchangeProductInfo.java
@@ -0,0 +1,34 @@
+package me.chanjar.weixin.channel.bean.after;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 换货商品信息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class AfterSaleExchangeProductInfo implements Serializable {
+
+  private static final long serialVersionUID = -1341436607011117854L;
+
+  /** 商品spuid */
+  @JsonProperty("product_id")
+  private String productId;
+
+  /** 旧商品skuid */
+  @JsonProperty("old_sku_id")
+  private String oldSkuId;
+
+  /** 新商品skuid */
+  @JsonProperty("new_sku_id")
+  private String newSkuId;
+
+  /** 数量 */
+  @JsonProperty("product_cnt")
+  private String productCnt;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/after/AfterSaleInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/after/AfterSaleInfo.java
index 3a9d390c95..d465766d75 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/after/AfterSaleInfo.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/after/AfterSaleInfo.java
@@ -86,4 +86,16 @@ public class AfterSaleInfo implements Serializable {
   /** 仅在待商家审核退款退货申请或收货期间返回，表示操作剩余时间（秒数）*/
   @JsonProperty("deadline")
   private Long deadline;
+
+  /** 售后换货商品信息 */
+  @JsonProperty("exchange_product_info")
+  private AfterSaleExchangeProductInfo exchangeProductInfo;
+
+  /** 售后换货物流信息 */
+  @JsonProperty("exchange_delivery_info")
+  private AfterSaleExchangeDeliveryInfo exchangeDeliveryInfo;
+
+  /** 售后换货虚拟号码信息 */
+  @JsonProperty("virtual_tel_num_info")
+  private AfterSaleVirtualNumberInfo virtualTelNumInfo;
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/after/AfterSaleListParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/after/AfterSaleListParam.java
index 78cc394085..a477a2c581 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/after/AfterSaleListParam.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/after/AfterSaleListParam.java
@@ -28,6 +28,14 @@ public class AfterSaleListParam implements Serializable {
   @JsonProperty("end_create_time")
   private Long endCreateTime;
 
+  /** 售后单更新起始时间 */
+  @JsonProperty("begin_update_time")
+  private Long beginUpdateTime;
+
+  /** 售后单更新结束时间，end_update_time减去begin_update_time不得大于24小时 */
+  @JsonProperty("end_update_time")
+  private Long endUpdateTime;
+
   /** 翻页参数，从第二页开始传，来源于上一页的返回值 */
   @JsonProperty("next_key")
   private String nextKey;
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/after/AfterSaleListResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/after/AfterSaleListResponse.java
index 3ad67cffcf..dde39238a7 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/after/AfterSaleListResponse.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/after/AfterSaleListResponse.java
@@ -14,7 +14,7 @@
  */
 @Data
 @NoArgsConstructor
-@EqualsAndHashCode
+@EqualsAndHashCode(callSuper = true)
 public class AfterSaleListResponse extends WxChannelBaseResponse {
 
   private static final long serialVersionUID = 5033313416948732123L;
@@ -23,6 +23,7 @@ public class AfterSaleListResponse extends WxChannelBaseResponse {
   private List<String> ids;
 
   /** 翻页参数 */
+  @JsonProperty("next_key")
   private String nextKey;
 
   /** 是否还有数据 */
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/after/AfterSaleVirtualNumberInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/after/AfterSaleVirtualNumberInfo.java
new file mode 100644
index 0000000000..4366fa5ce9
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/after/AfterSaleVirtualNumberInfo.java
@@ -0,0 +1,26 @@
+package me.chanjar.weixin.channel.bean.after;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 虚拟号码信息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class AfterSaleVirtualNumberInfo implements Serializable {
+  private static final long serialVersionUID = -5756618937333859985L;
+
+  /** 虚拟号码 */
+  @JsonProperty("virtual_tel_number")
+  private String virtualTelNumber;
+
+  /** 虚拟号码过期时间 */
+  @JsonProperty("virtual_tel_expire_time")
+  private Long virtualTelExpireTime;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/audit/CategoryAuditInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/audit/CategoryAuditInfo.java
index 72a84bc922..485092704d 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/audit/CategoryAuditInfo.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/audit/CategoryAuditInfo.java
@@ -1,5 +1,6 @@
 package me.chanjar.weixin.channel.bean.audit;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import java.io.Serializable;
 import java.util.List;
@@ -15,6 +16,7 @@
 @Data
 @NoArgsConstructor
 @AllArgsConstructor
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class CategoryAuditInfo implements Serializable {
 
   private static final long serialVersionUID = -8792967130645424788L;
@@ -31,7 +33,47 @@ public class CategoryAuditInfo implements Serializable {
   @JsonProperty("level3")
   private Long level3;
 
-  /** 资质材料，图片url，图片类型，最多不超过10张 */
+  /** 新类目树类目ID */
+  @JsonProperty("cats_v2")
+  private List<CatsV2> catsV2;
+
+  /** 资质材料，图片fileid，图片类型，最多不超过10张 */
   @JsonProperty("certificate")
   private List<String> certificates;
+
+  /** 报备函，图片fileid，图片类型，最多不超过10张 */
+  @JsonProperty("baobeihan")
+  private List<String> baobeihan;
+
+  /** 经营证明，图片fileid，图片类型，最多不超过10张 */
+  @JsonProperty("jingyingzhengming")
+  private List<String> jingyingzhengming;
+
+  /** 带货口碑，图片fileid，图片类型，最多不超过10张 */
+  @JsonProperty("daihuokoubei")
+  private List<String> daihuokoubei;
+
+  /** 入住资质，图片fileid，图片类型，最多不超过10张 */
+  @JsonProperty("ruzhuzhizhi")
+  private List<String> ruzhuzhizhi;
+
+  /** 经营流水，图片fileid，图片类型，最多不超过10张 */
+  @JsonProperty("jingyingliushui")
+  private List<String> jingyingliushui;
+
+  /** 补充材料，图片fileid，图片类型，最多不超过10张 */
+  @JsonProperty("buchongcailiao")
+  private List<String> buchongcailiao;
+
+  /** 经营平台，仅支持taobao，jd，douyin，kuaishou，pdd，other这些取值 */
+  @JsonProperty("jingyingpingtai")
+  private String jingyingpingtai;
+
+  /** 账号名称 */
+  @JsonProperty("zhanghaomingcheng")
+  private String zhanghaomingcheng;
+
+  /** 品牌列表，获取类目信息中的attr.is_limit_brand为true时必传 */
+  @JsonProperty("brand_list")
+  private List<CategoryBrand> brandList;
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/audit/CategoryBrand.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/audit/CategoryBrand.java
new file mode 100644
index 0000000000..632096e4d2
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/audit/CategoryBrand.java
@@ -0,0 +1,23 @@
+package me.chanjar.weixin.channel.bean.audit;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 分类中的品牌
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class CategoryBrand implements Serializable {
+  private static final long serialVersionUID = -5437441266080209907L;
+
+  /** 品牌ID，是店铺申请且已审核通过的品牌ID */
+  @JsonProperty("brand_id")
+  private String brand_id;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/audit/CatsV2.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/audit/CatsV2.java
new file mode 100644
index 0000000000..b7cc6f39bc
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/audit/CatsV2.java
@@ -0,0 +1,22 @@
+package me.chanjar.weixin.channel.bean.audit;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 新类目树类目ID
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class CatsV2 implements Serializable {
+  private static final long serialVersionUID = -2484092110142035589L;
+
+  /** 新类目树类目ID */
+  @JsonProperty("cat_id")
+  private String catId;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/CategoryDetailResult.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/CategoryDetailResult.java
index 8819e94312..32313b7e34 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/CategoryDetailResult.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/CategoryDetailResult.java
@@ -74,6 +74,38 @@ public static class Attr implements Serializable {
     /** 佣金信息 */
     @JsonProperty("transactionfee_info")
     private FeeInfo feeInfo;
+
+    /** 折扣规则 */
+    @JsonProperty("coupon_rule")
+    private CouponRule couponRule;
+
+    /** 价格下限，单位分，商品售价不可低于此价格 */
+    @JsonProperty("floor_price")
+    private Long floorPrice;
+
+    /** 收货时间选项 */
+    @JsonProperty("confirm_receipt_days")
+    private List<String> confirmReceiptDays;
+
+    /** 是否品牌定向准入，即该类目一定要有品牌 */
+    @JsonProperty("is_limit_brand")
+    private Boolean limitBrand;
+
+    /** 商品编辑要求 */
+    @JsonProperty("product_requirement")
+    private ProductRequirement productRequirement;
+
+    /** 尺码表 */
+    @JsonProperty("size_chart")
+    private SizeChart sizeChart;
+
+    /** 放心买必须打开坏损包赔 */
+    @JsonProperty("is_confidence_require_bad_must_pay")
+    private Boolean confidenceRequireBadMustPay;
+
+    /** 资质信息 */
+    @JsonProperty("product_qua_list")
+    private List<QualificationInfo> productQuaList;
   }
 
   @Data
@@ -93,11 +125,27 @@ public static class ProductAttr implements Serializable {
     @JsonProperty("name")
     private String name;
 
-    /** 类目必填项类型，string为自定义，select_one为多选一 */
+    /** 属性类型，string为自定义，select_one为多选一，该参数短期保留，用于兼容。将来废弃，使用type_v2替代 */
     @JsonProperty("type")
     private String type;
 
-    /** 类目必填项值 */
+    /**
+     * 属性类型v2，共7种类型
+     * string：文本
+     * select_one：单选，选项列表在value中
+     * select_many：多选，选项列表在value中
+     * integer：整数，数字必须为整数
+     * decimal4：小数（4 位精度），小数部分最多 4 位
+     * integer_unit：整数 + 单位，单位的选项列表在value中
+     * decimal4_unit：小数（4 位精度） + 单位，单位的选项列表在value中
+     */
+    @JsonProperty("type_v2")
+    private String typeV2;
+
+    /**
+     * 可选项列表，当type为：select_one/select_many时，为选项列表
+     * 当type为：integer_unit/decimal4_unit时，为单位的列表
+     */
     @JsonProperty("value")
     private String value;
 
@@ -105,7 +153,13 @@ public static class ProductAttr implements Serializable {
     @JsonProperty("is_required")
     private Boolean required;
 
+    /** 输入提示，请填写提示语 */
+    @JsonProperty("hint")
+    private String hint;
 
+    /** 允许添加选项，当type为select_one/select_many时，标识是否允许添加新选项（value中不存在的选项） */
+    @JsonProperty("append_allowed")
+    private Boolean appendAllowed;
   }
 
   @Data
@@ -123,8 +177,78 @@ public static class FeeInfo implements Serializable {
     /** 佣金激励类型，0：无激励措施，1：新店佣金减免 */
     @JsonProperty("incentive_type")
     private Integer incentiveType;
+  }
+
+  @Data
+  @NoArgsConstructor
+  public static class CouponRule implements Serializable {
+
+    /** 最高的折扣比例，百分比, 0表示无限制 */
+    @JsonProperty("discount_ratio_limit")
+    private Integer supportCoupon;
+
+    /** 最高的折扣金额，单位分，0表示无限制 */
+    @JsonProperty("discount_limit")
+    private Integer couponType;
+  }
 
+  @Data
+  @NoArgsConstructor
+  public static class ProductRequirement implements Serializable {
+    /** 商品标题的编辑要求 */
+    @JsonProperty("product_title_requirement")
+    private String productTitleRequirement;
+
+    /** 商品主图的编辑要求 */
+    @JsonProperty("product_img_requirement")
+    private String productImgRequirement;
+
+    /** 商品描述的编辑要求 */
+    @JsonProperty("product_desc_requirement")
+    private String productDescRequirement;
   }
+
+  @Data
+  @NoArgsConstructor
+  public static class SizeChart implements Serializable {
+
+    /** 是否支持尺码表 */
+    @JsonProperty("is_support")
+    private Boolean support;
+
+    /** 尺码配置要求列表 */
+    @JsonProperty("item_list")
+    private List<SizeChartItem> itemList;
+  }
+
+  @Data
+  @NoArgsConstructor
+  public static class SizeChartItem implements Serializable {
+    /** 尺码属性名称 */
+    @JsonProperty("name")
+    private String name;
+
+    /** 尺码属性值的单位 */
+    @JsonProperty("unit")
+    private String unit;
+
+    /** 尺码属性值的类型，1：字符型，2：整数型，3：小数型 */
+    @JsonProperty("type")
+    private String type;
+
+    /** 尺码属性值的填写格式，1：单值填写，2：区间值填写，3：支持单值或区间值 */
+    @JsonProperty("format")
+    private String format;
+
+    /** 尺码属性值的限制 */
+    @JsonProperty("limit")
+    private String limit;
+
+    /** 是否必填 */
+    @JsonProperty("is_required")
+    private Boolean required;
+  }
+
 }
 
 
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/CategoryQualification.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/CategoryQualification.java
index f384eaae45..9cac327d6c 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/CategoryQualification.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/CategoryQualification.java
@@ -2,6 +2,7 @@
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 import java.io.Serializable;
+import java.util.List;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
@@ -24,8 +25,22 @@ public class CategoryQualification implements Serializable {
   @JsonProperty("qua")
   private QualificationInfo info;
 
-  /** 商品资质信息 */
+  /** 商品资质信息，将废弃，使用product_qua_list代替 */
   @JsonProperty("product_qua")
+  @Deprecated
   private QualificationInfo productInfo;
 
+  /** 品牌资质信息 */
+  @JsonProperty("brand_qua")
+  @Deprecated
+  private QualificationInfo brandQua;
+
+  /** 商品资质列表，替代product_qua */
+  @JsonProperty("product_qua_list")
+  private List<QualificationInfo> productQuaList;
+
+  /** 放心买必须打开坏损包赔 */
+  @JsonProperty("is_confidence_require_bad_must_pay")
+  private Boolean confidenceRequireBadMustPay;
+
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/CategoryQualificationResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/CategoryQualificationResponse.java
index 984a3ad79b..cbd588ebf9 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/CategoryQualificationResponse.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/CategoryQualificationResponse.java
@@ -22,4 +22,7 @@ public class CategoryQualificationResponse extends WxChannelBaseResponse {
   @JsonProperty("cats")
   private List<CategoryAndQualificationList> list;
 
+  @JsonProperty("cats_v2")
+  private List<CategoryAndQualificationList> catsV2;
+
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/PassCategoryResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/PassCategoryResponse.java
index af6f484254..6509321b88 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/PassCategoryResponse.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/PassCategoryResponse.java
@@ -3,6 +3,7 @@
 import com.fasterxml.jackson.annotation.JsonProperty;
 import java.util.List;
 import lombok.Data;
+import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
 import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
 
@@ -13,6 +14,7 @@
  */
 @Data
 @NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
 public class PassCategoryResponse extends WxChannelBaseResponse {
 
   private static final long serialVersionUID = -3674591447273025743L;
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/QualificationInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/QualificationInfo.java
index 197ac46528..efb7249fe3 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/QualificationInfo.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/QualificationInfo.java
@@ -29,4 +29,8 @@ public class QualificationInfo implements Serializable {
   /** 该类目申请的时候是否一定要提交资质 */
   @JsonProperty("mandatory")
   private Boolean mandatory;
+
+  /** 资质名称 */
+  @JsonProperty("name")
+  private String name;
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/ShopCategory.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/ShopCategory.java
index b36edfa9e2..5dd04582f3 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/ShopCategory.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/ShopCategory.java
@@ -29,4 +29,8 @@ public class ShopCategory implements Serializable {
   /** 层级 */
   @JsonProperty("level")
   private Integer level;
+
+  /** 是否为叶子类目（品类） */
+  @JsonProperty("leaf")
+  private Boolean leaf;
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/ShopCategoryResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/ShopCategoryResponse.java
index 2af64ad1c3..fff7362a7a 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/ShopCategoryResponse.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/category/ShopCategoryResponse.java
@@ -23,5 +23,7 @@ public class ShopCategoryResponse extends WxChannelBaseResponse {
   @JsonProperty("cat_list")
   private List<ShopCategory> categories;
 
-
+  /** 类目列表 */
+  @JsonProperty("cat_list_v2")
+  private List<ShopCategory> catListV2;
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/finder/CompassFinderBaseParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/CompassFinderBaseParam.java
similarity index 92%
rename from weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/finder/CompassFinderBaseParam.java
rename to weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/CompassFinderBaseParam.java
index 78e088f9ec..a1d5e277cc 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/finder/CompassFinderBaseParam.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/CompassFinderBaseParam.java
@@ -1,4 +1,4 @@
-package me.chanjar.weixin.channel.bean.compass.finder;
+package me.chanjar.weixin.channel.bean.compass;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/finder/ProductDataParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/finder/ProductDataParam.java
index bddb9f3356..57a26a9794 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/finder/ProductDataParam.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/finder/ProductDataParam.java
@@ -5,6 +5,7 @@
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.compass.CompassFinderBaseParam;
 
 /**
  * 获取带货商品数据请求参数
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/finder/SaleProfileDataParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/finder/SaleProfileDataParam.java
index 57a5854e71..abe4610785 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/finder/SaleProfileDataParam.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/finder/SaleProfileDataParam.java
@@ -5,6 +5,7 @@
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.compass.CompassFinderBaseParam;
 
 /**
  * 获取带货人群数据请求参数
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/CompassFinderIdParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/CompassFinderIdParam.java
new file mode 100644
index 0000000000..9383d2de2f
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/CompassFinderIdParam.java
@@ -0,0 +1,32 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.compass.CompassFinderBaseParam;
+
+/**
+ * 带货达人 请求参数
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class CompassFinderIdParam extends CompassFinderBaseParam {
+
+  private static final long serialVersionUID = 9214560943091074780L;
+
+  /** 视频号ID */
+  @JsonProperty("finder_id")
+  private String finderId;
+
+  public CompassFinderIdParam(String ds, String finderId) {
+    super(ds);
+    this.finderId = finderId;
+  }
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderAuthListResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderAuthListResponse.java
new file mode 100644
index 0000000000..0f0351e975
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderAuthListResponse.java
@@ -0,0 +1,30 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.List;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 获取授权视频号列表 响应
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class FinderAuthListResponse extends WxChannelBaseResponse {
+
+  private static final long serialVersionUID = -3215073536002857589L;
+
+  /** 主营视频号id */
+  @JsonProperty("main_finder_id")
+  private String mainFinderId;
+
+  /** 授权视频号id列表 */
+  @JsonProperty("authorized_finder_id_list")
+  private List<String> authorizedFinderIdList;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderGmvData.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderGmvData.java
new file mode 100644
index 0000000000..822f93c4f0
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderGmvData.java
@@ -0,0 +1,39 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 带货达人数据
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class FinderGmvData implements Serializable {
+
+  private static final long serialVersionUID = -7463331971169286175L;
+
+  /** 成交金额，单位分 */
+  @JsonProperty("pay_gmv")
+  private String payGmv;
+
+  /** 动销商品数 */
+  @JsonProperty("pay_product_id_cnt")
+  private String payProductIdCnt;
+
+  /** 成交人数 */
+  @JsonProperty("pay_uv")
+  private String payUv;
+
+  /** 退款金额，单位分 */
+  @JsonProperty("refund_gmv")
+  private String refundGmv;
+
+  /** 成交退款金额，单位分 */
+  @JsonProperty("pay_refund_gmv")
+  private String payRefundGmv;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderGmvItem.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderGmvItem.java
new file mode 100644
index 0000000000..a102732c8a
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderGmvItem.java
@@ -0,0 +1,30 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 带货达人列表数据
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class FinderGmvItem implements Serializable {
+
+  private static final long serialVersionUID = -3740996985044711599L;
+
+  /** 视频号id */
+  @JsonProperty("finder_id")
+  private String finderId;
+
+  /** 视频号昵称 */
+  @JsonProperty("finder_nickname")
+  private String finderNickname;
+
+  /** 带货达人数据 */
+  @JsonProperty("data")
+  private FinderGmvData data;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderListResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderListResponse.java
new file mode 100644
index 0000000000..a5a37d9a2f
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderListResponse.java
@@ -0,0 +1,26 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.List;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 带货达人列表 响应
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class FinderListResponse extends WxChannelBaseResponse {
+
+  private static final long serialVersionUID = 6358992001065379269L;
+
+  /** 授权视频号id列表 */
+  @JsonProperty("finder_list")
+  private List<FinderGmvItem> finderList;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderOverallData.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderOverallData.java
new file mode 100644
index 0000000000..6303202709
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderOverallData.java
@@ -0,0 +1,35 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 带货数据概览
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class FinderOverallData implements Serializable {
+
+  private static final long serialVersionUID = -994852668593815907L;
+
+  /** 成交金额，单位分 */
+  @JsonProperty("pay_gmv")
+  private String payGmv;
+
+  /** 动销达人数 */
+  @JsonProperty("pay_sales_finder_cnt")
+  private String paySalesFinderCnt;
+
+  /** 动销商品数 */
+  @JsonProperty("pay_product_id_cnt")
+  private String payProductIdCnt;
+
+  /** 点击-成交转化率 */
+  @JsonProperty("click_to_pay_uv_ratio")
+  private Double clickToPayUvRatio;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderOverallResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderOverallResponse.java
new file mode 100644
index 0000000000..fdc83fcce8
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderOverallResponse.java
@@ -0,0 +1,26 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 带货数据概览 响应
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class FinderOverallResponse extends WxChannelBaseResponse {
+
+  private static final long serialVersionUID = -4935555091396799318L;
+
+  /**
+   * 电商概览数据
+   */
+  @JsonProperty("data")
+  private FinderOverallData data;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderProductListItem.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderProductListItem.java
new file mode 100644
index 0000000000..7f6ad34445
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderProductListItem.java
@@ -0,0 +1,66 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 带货达人商品列表
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class FinderProductListItem implements Serializable {
+
+  private static final long serialVersionUID = 1646092488200992026L;
+
+  /** 商品id */
+  @JsonProperty("product_id")
+  private String productId;
+
+  /** 商品头图 */
+  @JsonProperty("head_img_url")
+  private String headImgUrl;
+
+  /** 商品标题 */
+  @JsonProperty("title")
+  private String title;
+
+  /** 商品价格 */
+  @JsonProperty("price")
+  private String price;
+
+  /** 商品1级类目 */
+  @JsonProperty("first_category_id")
+  private String firstCategoryId;
+
+  /** 商品2级类目 */
+  @JsonProperty("second_category_id")
+  private String secondCategoryId;
+
+  /** 商品3级类目 */
+  @JsonProperty("third_category_id")
+  private String thirdCategoryId;
+
+  /** gmv */
+  @JsonProperty("data")
+  private GmvData data;
+
+
+  @Data
+  @NoArgsConstructor
+  public static class GmvData implements Serializable {
+    private static final long serialVersionUID = 1840494188469233735L;
+
+    /** 佣金率 */
+    @JsonProperty("commission_ratio")
+    private Double commissionRatio;
+
+    /** 成交金额，单位分 */
+    @JsonProperty("pay_gmv")
+    private String payGmv;
+  }
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderProductListResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderProductListResponse.java
new file mode 100644
index 0000000000..bcdb1932d4
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderProductListResponse.java
@@ -0,0 +1,28 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.List;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 带货达人商品列表 响应
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class FinderProductListResponse extends WxChannelBaseResponse {
+
+  private static final long serialVersionUID = 5883861777181983173L;
+
+  /**
+   * 带货达人商品列表
+   */
+  @JsonProperty("product_list")
+  private List<FinderProductListItem> productList;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderProductOverallResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderProductOverallResponse.java
new file mode 100644
index 0000000000..e47223a4d8
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderProductOverallResponse.java
@@ -0,0 +1,25 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 带货达人详情 响应
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class FinderProductOverallResponse extends WxChannelBaseResponse {
+
+  private static final long serialVersionUID = 6358992001065379269L;
+
+  /** 带货达人详情 */
+  @JsonProperty("data")
+  private FinderGmvData data;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderProductSimpleGmvData.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderProductSimpleGmvData.java
new file mode 100644
index 0000000000..7a635dc4b0
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/FinderProductSimpleGmvData.java
@@ -0,0 +1,26 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 带货达人商品GMV数据
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class FinderProductSimpleGmvData implements Serializable {
+  private static final long serialVersionUID = -3740996985044711599L;
+
+  /** 佣金率 */
+  @JsonProperty("commission_ratio")
+  private Double commissionRatio;
+
+  /** 成交金额，单位分 */
+  @JsonProperty("pay_gmv")
+  private String payGmv;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopField.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopField.java
new file mode 100644
index 0000000000..4acd91ace0
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopField.java
@@ -0,0 +1,44 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.List;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 维度数据
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class ShopField implements Serializable {
+
+  private static final long serialVersionUID = -8669197081350262569L;
+
+  /** 维度类别名 */
+  @JsonProperty("field_name")
+  private String fieldName;
+
+  /** 维度指标数据列表 */
+  @JsonProperty("data_list")
+  private List<FieldDetail> dataList;
+
+
+  @Data
+  @NoArgsConstructor
+  public static class FieldDetail implements Serializable {
+
+    private static final long serialVersionUID = 2900633035074950462L;
+
+    /** 维度指标名 */
+    @JsonProperty("dim_key")
+    private String dimKey;
+
+    /** 维度指标值 */
+    @JsonProperty("dim_value")
+    private String dimValue;
+
+  }
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopLiveData.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopLiveData.java
new file mode 100644
index 0000000000..d6a7b99451
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopLiveData.java
@@ -0,0 +1,36 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 店铺开播数据
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class ShopLiveData implements Serializable {
+
+  /** 直播id */
+  @JsonProperty("live_id")
+  private String liveId;
+
+  /** 直播标题 */
+  @JsonProperty("live_title")
+  private String liveTitle;
+
+  /** 开播时间，unix时间戳 */
+  @JsonProperty("live_time")
+  private String liveTime;
+
+  /** 直播时长，单位秒 */
+  @JsonProperty("live_duration")
+  private String liveDuration;
+
+  /** 直播封面 */
+  @JsonProperty("live_cover_img_url")
+  private String liveCoverImgUrl;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopLiveListResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopLiveListResponse.java
new file mode 100644
index 0000000000..3ec9b68772
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopLiveListResponse.java
@@ -0,0 +1,26 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.List;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 店铺开播列表 响应
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class ShopLiveListResponse extends WxChannelBaseResponse {
+
+  private static final long serialVersionUID = -7110751559923117330L;
+
+  /** 店铺开播列表 */
+  @JsonProperty("live_list")
+  private List<ShopLiveData> liveList;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopOverall.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopOverall.java
new file mode 100644
index 0000000000..bf2fc8f42f
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopOverall.java
@@ -0,0 +1,42 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 电商概览数据
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class ShopOverall implements Serializable {
+
+  private static final long serialVersionUID = 3304918097895132226L;
+
+  /** 成交金额，单位分 */
+  @JsonProperty("pay_gmv")
+  private String payGmv;
+
+  /** 成交人数 */
+  @JsonProperty("pay_uv")
+  private String payUv;
+
+  /** 成交退款金额，单位分 */
+  @JsonProperty("pay_refund_gmv")
+  private String payRefundGmv;
+
+  /** 成交订单数 */
+  @JsonProperty("pay_order_cnt")
+  private String payOrderCnt;
+
+  /** 直播成交金额，单位分 */
+  @JsonProperty("live_pay_gmv")
+  private String livePayGmv;
+
+  /** 短视频成交金额，单位分 */
+  @JsonProperty("feed_pay_gmv")
+  private String feedPayGmv;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopOverallResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopOverallResponse.java
new file mode 100644
index 0000000000..4b371454ca
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopOverallResponse.java
@@ -0,0 +1,27 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 获取电商概览数据响应
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class ShopOverallResponse extends WxChannelBaseResponse {
+
+  private static final long serialVersionUID = 1632800741359642057L;
+
+  /**
+   * 电商概览数据
+   */
+  @JsonProperty("data")
+  private ShopOverall data;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopProductCompassData.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopProductCompassData.java
new file mode 100644
index 0000000000..03253e399e
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopProductCompassData.java
@@ -0,0 +1,143 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 店铺商品罗盘数据
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class ShopProductCompassData implements Serializable {
+
+  private static final long serialVersionUID = 5387546181020447627L;
+
+  /** 成交金额 */
+  @JsonProperty("pay_gmv")
+  private String payGmv;
+
+  /**下单金额，单位分 */
+  @JsonProperty("create_gmv")
+  private String createGmv;
+
+  /** 下单订单数 */
+  @JsonProperty("create_cnt")
+  private String createCnt;
+
+  /** 下单人数 */
+  @JsonProperty("create_uv")
+  private String createUv;
+
+  /** 下单件数 */
+  @JsonProperty("create_product_cnt")
+  private String createProductCnt;
+
+  /** 成交订单数 */
+  @JsonProperty("pay_cnt")
+  private String payCnt;
+
+  /** 成交人数 */
+  @JsonProperty("pay_uv")
+  private String payUv;
+
+  /** 成交件数 */
+  @JsonProperty("pay_product_cnt")
+  private String payProductCnt;
+
+  /** 成交金额（剔除退款） */
+  @JsonProperty("pure_pay_gmv")
+  private String purePayGmv;
+
+  /** 成交客单价（剔除退款） */
+  @JsonProperty("pay_gmv_per_uv")
+  private String payGmvPerUv;
+
+  /** 实际结算金额，单位分 */
+  @JsonProperty("seller_actual_settle_amount")
+  private String sellerActualSettleAmount;
+
+  /** 实际服务费金额，单位分 */
+  @JsonProperty("platform_actual_commission")
+  private String platformActualCommission;
+
+  /** 实际达人佣金支出，单位分 */
+  @JsonProperty("finderuin_actual_commission")
+  private String finderuinActualCommission;
+
+  /** 实际团长佣金支出，单位分 */
+  @JsonProperty("captain_actual_commission")
+  private String captainActualCommission;
+
+  /** 预估结算金额，单位分 */
+  @JsonProperty("seller_predict_settle_amount")
+  private String sellerPredictSettleAmount;
+
+  /** 预估服务费金额，单位分 */
+  @JsonProperty("platform_predict_commission")
+  private String platformPredictCommission;
+
+  /** 预估达人佣金支出，单位分 */
+  @JsonProperty("finderuin_predict_commission")
+  private String finderuinPredictCommission;
+
+  /** 预估团长佣金支出，单位分 */
+  @JsonProperty("captain_predict_commission")
+  private String captainPredictCommission;
+
+  /** 商品点击人数 */
+  @JsonProperty("product_click_uv")
+  private String productClickUv;
+
+  /** 商品点击次数 */
+  @JsonProperty("product_click_cnt")
+  private String productClickCnt;
+
+  /** 成交退款金额，单位分 */
+  @JsonProperty("pay_refund_gmv")
+  private String payRefundGmv;
+
+  /** 成交退款人数，单位分 */
+  @JsonProperty("pay_refund_uv")
+  private String payRefundUv;
+
+  /** 成交退款率 */
+  @JsonProperty("pay_refund_ratio")
+  private Double payRefundRatio;
+
+  /** 发货后成交退款率 */
+  @JsonProperty("pay_refund_after_send_ratio")
+  private Double payRefundAfterSendRatio;
+
+  /** 成交退款订单数 */
+  @JsonProperty("pay_refund_cnt")
+  private String payRefundCnt;
+
+  /** 成交退款件数 */
+  @JsonProperty("pay_refund_product_cnt")
+  private String payRefundProductCnt;
+
+  /** 发货前成交退款率 */
+  @JsonProperty("pay_refund_before_send_ratio")
+  private Double payRefundBeforeSendRatio;
+
+  /** 退款金额，单位分 */
+  @JsonProperty("refund_gmv")
+  private String refundGmv;
+
+  /** 退款件数 */
+  @JsonProperty("refund_product_cnt")
+  private String refundProductCnt;
+
+  /** 退款订单数 */
+  @JsonProperty("refund_cnt")
+  private String refundCnt;
+
+  /** 退款人数 */
+  @JsonProperty("refund_uv")
+  private String refundUv;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopProductDataParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopProductDataParam.java
new file mode 100644
index 0000000000..74d7306273
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopProductDataParam.java
@@ -0,0 +1,32 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.compass.CompassFinderBaseParam;
+
+/**
+ * 商品数据 请求参数
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class ShopProductDataParam extends CompassFinderBaseParam {
+
+  private static final long serialVersionUID = - 5016298274452168329L;
+
+  /** 商品id */
+  @JsonProperty("product_id")
+  private String productId;
+
+  public ShopProductDataParam(String ds, String productId) {
+    super(ds);
+    this.productId = productId;
+  }
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopProductDataResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopProductDataResponse.java
new file mode 100644
index 0000000000..bd7a22d243
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopProductDataResponse.java
@@ -0,0 +1,26 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 商品详细信息 响应
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class ShopProductDataResponse extends WxChannelBaseResponse {
+
+  private static final long serialVersionUID = 6903392663954301579L;
+
+  /** 商品详细信息 */
+  @JsonProperty("product_info")
+  private ShopProductInfo productInfo;
+
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopProductInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopProductInfo.java
new file mode 100644
index 0000000000..1eb55eaa75
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopProductInfo.java
@@ -0,0 +1,51 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 店铺带货商品数据
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class ShopProductInfo implements Serializable {
+
+  private static final long serialVersionUID = 3376047696301017643L;
+
+  /** 商品id */
+  @JsonProperty("product_id")
+  private String productId;
+
+  /** 商品图 */
+  @JsonProperty("head_img_url")
+  private String headImgUrl;
+
+  /** 商品标题 */
+  @JsonProperty("title")
+  private String title;
+
+  /** 商品价格，单位分 */
+  @JsonProperty("price")
+  private String price;
+
+  /** 商品一级类目 */
+  @JsonProperty("first_category_id")
+  private String firstCategoryId;
+
+  /** 商品二级类目 */
+  @JsonProperty("second_category_id")
+  private String secondCategoryId;
+
+  /** 商品三级类目 */
+  @JsonProperty("third_category_id")
+  private String thirdCategoryId;
+
+  /** 商品罗盘数据 */
+  @JsonProperty("data")
+  private ShopProductCompassData data;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopProductListResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopProductListResponse.java
new file mode 100644
index 0000000000..258b8f5845
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopProductListResponse.java
@@ -0,0 +1,26 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.List;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 商品列表 响应
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class ShopProductListResponse extends WxChannelBaseResponse {
+
+  private static final long serialVersionUID = -6328224902770141045L;
+
+  /** 商品列表 */
+  @JsonProperty("product_list")
+  private List<ShopProductInfo> productList;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopSaleProfileData.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopSaleProfileData.java
new file mode 100644
index 0000000000..23639c5356
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopSaleProfileData.java
@@ -0,0 +1,24 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.List;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 店铺人群数据
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class ShopSaleProfileData implements Serializable {
+
+  private static final long serialVersionUID = -6825849811081728787L;
+
+  /** 维度数据列表 */
+  @JsonProperty("field_list")
+  private List<ShopField> fieldList;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopSaleProfileDataParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopSaleProfileDataParam.java
new file mode 100644
index 0000000000..36cab13860
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopSaleProfileDataParam.java
@@ -0,0 +1,32 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.compass.CompassFinderBaseParam;
+
+/**
+ * 获取带货人群数据请求参数
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class ShopSaleProfileDataParam extends CompassFinderBaseParam {
+
+  private static final long serialVersionUID = 240010632808576923L;
+
+  /** 用户类型 */
+  @JsonProperty("type")
+  private Integer type;
+
+  public ShopSaleProfileDataParam(String ds, Integer type) {
+    super(ds);
+    this.type = type;
+  }
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopSaleProfileDataResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopSaleProfileDataResponse.java
new file mode 100644
index 0000000000..a874cd6355
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/compass/shop/ShopSaleProfileDataResponse.java
@@ -0,0 +1,25 @@
+package me.chanjar.weixin.channel.bean.compass.shop;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 店铺人群数据 响应
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class ShopSaleProfileDataResponse extends WxChannelBaseResponse {
+
+  private static final long serialVersionUID = 8520148855114842741L;
+
+  /** 店铺人群数据 */
+  @JsonProperty("data")
+  private ShopSaleProfileData data;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/cooperation/CooperationData.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/cooperation/CooperationData.java
new file mode 100644
index 0000000000..41020f4993
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/cooperation/CooperationData.java
@@ -0,0 +1,47 @@
+package me.chanjar.weixin.channel.bean.cooperation;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 合作账号信息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class CooperationData implements Serializable {
+
+  private static final long serialVersionUID = 3930010847236599458L;
+
+  /** 合作账号id 公众号: gh_开头id 小程序: appid */
+  @JsonProperty("sharer_id")
+  private String sharerId;
+
+  /** 邀请/合作账号状态 1已绑定 2已解绑 3邀请已拒绝 4邀请接受中 5邀请接受超时 6邀请接受失败 7邀请店铺取消 */
+  @JsonProperty("status")
+  private Integer status;
+
+  /** 合作账号名称 */
+  @JsonProperty("sharer_name")
+  private String sharerName;
+
+  /** 合作账号类型 2公众号 3小程序 */
+  @JsonProperty("sharer_type")
+  private Integer sharerType;
+
+  /** 接受绑定时间戳，ms */
+  @JsonProperty("bind_time")
+  private Long bindTime;
+
+  /** 用户拒绝时间戳，ms */
+  @JsonProperty("reject_time")
+  private Long rejectTime;
+
+  /** 商家取消时间戳，ms */
+  @JsonProperty("cancel_time")
+  private Long cancelTime;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/cooperation/CooperationListResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/cooperation/CooperationListResponse.java
new file mode 100644
index 0000000000..1b652b64d6
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/cooperation/CooperationListResponse.java
@@ -0,0 +1,25 @@
+package me.chanjar.weixin.channel.bean.cooperation;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.List;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 合作账号列表响应
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class CooperationListResponse extends WxChannelBaseResponse {
+
+  private static final long serialVersionUID = 6998637882644598826L;
+
+  /** 合作账号列表 */
+  @JsonProperty("data_list")
+  private List<CooperationData> dataList;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/cooperation/CooperationQrCode.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/cooperation/CooperationQrCode.java
new file mode 100644
index 0000000000..272b9802da
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/cooperation/CooperationQrCode.java
@@ -0,0 +1,23 @@
+package me.chanjar.weixin.channel.bean.cooperation;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 合作账号二维码数据
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class CooperationQrCode implements Serializable {
+
+  private static final long serialVersionUID = -7096916911986699150L;
+
+  /** base64编码后的图片数据 */
+  @JsonProperty("qrcode_base64")
+  private Integer qrCodeBase64;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/cooperation/CooperationQrCodeResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/cooperation/CooperationQrCodeResponse.java
new file mode 100644
index 0000000000..b18b2b1c85
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/cooperation/CooperationQrCodeResponse.java
@@ -0,0 +1,24 @@
+package me.chanjar.weixin.channel.bean.cooperation;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 合作账号二维码响应
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class CooperationQrCodeResponse extends WxChannelBaseResponse {
+
+  private static final long serialVersionUID = 6998637882644598826L;
+
+  /** 合作账号二维码 */
+  @JsonProperty("data")
+  private CooperationQrCode data;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/cooperation/CooperationSharerParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/cooperation/CooperationSharerParam.java
new file mode 100644
index 0000000000..4ca9bd8344
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/cooperation/CooperationSharerParam.java
@@ -0,0 +1,30 @@
+package me.chanjar.weixin.channel.bean.cooperation;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 合作账号参数
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class CooperationSharerParam implements Serializable {
+
+  private static final long serialVersionUID = 5032621997764493109L;
+
+  /** 合作账号id */
+  @JsonProperty("sharer_id")
+  private String sharerId;
+
+  /** 合作账号类型 */
+  @JsonProperty("sharer_type")
+  private Integer sharerType;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/cooperation/CooperationStatus.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/cooperation/CooperationStatus.java
new file mode 100644
index 0000000000..5267be6153
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/cooperation/CooperationStatus.java
@@ -0,0 +1,23 @@
+package me.chanjar.weixin.channel.bean.cooperation;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 合作账号状态
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class CooperationStatus implements Serializable {
+
+  private static final long serialVersionUID = -7096916911986699150L;
+
+  /** 邀请/合作账号状态 1已绑定 2已解绑 3邀请已拒绝 4邀请接受中 5邀请接受超时 6邀请接受失败 7邀请店铺取消 */
+  @JsonProperty("status")
+  private Integer status;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/cooperation/CooperationStatusResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/cooperation/CooperationStatusResponse.java
new file mode 100644
index 0000000000..6507340c63
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/cooperation/CooperationStatusResponse.java
@@ -0,0 +1,24 @@
+package me.chanjar.weixin.channel.bean.cooperation;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 合作账号状态响应
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class CooperationStatusResponse extends WxChannelBaseResponse {
+
+  private static final long serialVersionUID = 6998637882644598826L;
+
+  /** 合作账号状态 */
+  @JsonProperty("data")
+  private CooperationStatus data;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/delivery/FreshInspectParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/delivery/FreshInspectParam.java
new file mode 100644
index 0000000000..a6db90f2f9
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/delivery/FreshInspectParam.java
@@ -0,0 +1,31 @@
+package me.chanjar.weixin.channel.bean.delivery;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.List;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 商品打包信息 参数
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@JsonInclude(Include.NON_NULL)
+public class FreshInspectParam implements Serializable {
+  private static final long serialVersionUID = -1635894867602084789L;
+
+  /** 订单ID */
+  @JsonProperty("order_id")
+  private String orderId;
+
+  /** 商品打包信息 */
+  @JsonProperty("audit_items")
+  private List<PackageAuditInfo> auditItems;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/delivery/PackageAuditInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/delivery/PackageAuditInfo.java
new file mode 100644
index 0000000000..bbb4e6c484
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/delivery/PackageAuditInfo.java
@@ -0,0 +1,32 @@
+package me.chanjar.weixin.channel.bean.delivery;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.enums.PackageAuditItemType;
+
+/**
+ * 商品打包信息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class PackageAuditInfo implements Serializable {
+  private static final long serialVersionUID = 1118087167138310282L;
+
+  /**
+   * 审核项名称，枚举类型参考 {@link PackageAuditItemType}
+   * 使用方法：DeliveryAuditItemType.EXPRESS_PIC.getKey()
+   */
+  @JsonProperty("item_name")
+  private String itemName;
+
+  /** 图片/视频url */
+  @JsonProperty("item_value")
+  private String itemValue;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/freight/ConditionFreeDetail.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/freight/ConditionFreeDetail.java
index 68cb3b146e..cd0b76990d 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/freight/ConditionFreeDetail.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/freight/ConditionFreeDetail.java
@@ -20,11 +20,11 @@ public class ConditionFreeDetail extends AddressInfoList {
   @JsonProperty("min_piece")
   private Integer minPiece;
 
-  /** 最低重量 */
+  /** 最低重量，单位千克，订单商品总质量小于一千克，算作一千克 */
   @JsonProperty("min_weight")
   private Double minWeight;
 
-  /** 最低金额 */
+  /** 最低金额，单位（分） */
   @JsonProperty("min_amount")
   private Integer minAmount;
 
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/background/BackgroundApplyResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/background/BackgroundApplyResponse.java
new file mode 100644
index 0000000000..b0d8769874
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/background/BackgroundApplyResponse.java
@@ -0,0 +1,25 @@
+package me.chanjar.weixin.channel.bean.home.background;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 提交背景图申请 结果
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class BackgroundApplyResponse extends WxChannelBaseResponse {
+
+  private static final long serialVersionUID = -5627456997199822109L;
+
+  /** 申请编号 */
+  @JsonProperty("apply_id")
+  private Integer applyId;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/background/BackgroundApplyResult.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/background/BackgroundApplyResult.java
new file mode 100644
index 0000000000..45ca4ac1dd
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/background/BackgroundApplyResult.java
@@ -0,0 +1,35 @@
+package me.chanjar.weixin.channel.bean.home.background;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 背景图审核信息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class BackgroundApplyResult implements Serializable {
+
+  private static final long serialVersionUID = 3154900058221168732L;
+
+  /** 申请编号 */
+  @JsonProperty("apply_id")
+  private Integer applyId;
+
+  /** 申请状态。1审核中 2审核驳回 */
+  @JsonProperty("state")
+  private Integer state;
+
+  /** 审核结果描述。state为审核驳回时有值。 */
+  @JsonProperty("audit_desc")
+  private String auditDesc;
+
+  /** 图片url */
+  @JsonProperty("img_url")
+  private String imgUrl;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/background/BackgroundGetResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/background/BackgroundGetResponse.java
new file mode 100644
index 0000000000..a0fbf33a80
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/background/BackgroundGetResponse.java
@@ -0,0 +1,28 @@
+package me.chanjar.weixin.channel.bean.home.background;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 背景图返回结果
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class BackgroundGetResponse extends WxChannelBaseResponse {
+
+  private static final long serialVersionUID = -9158761351220981959L;
+
+  /** 当前生效的背景图片url */
+  @JsonProperty("img_url")
+  private String imgUrl;
+
+  /** 背景图审核信息 */
+  @JsonProperty("apply")
+  private BackgroundApplyResult apply;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerApplyDetail.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerApplyDetail.java
new file mode 100644
index 0000000000..e9e58057fd
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerApplyDetail.java
@@ -0,0 +1,33 @@
+package me.chanjar.weixin.channel.bean.home.banner;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 精选展示位申请详情
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@JsonInclude(Include.NON_NULL)
+public class BannerApplyDetail implements Serializable {
+
+  private static final long serialVersionUID = -4622897527243343862L;
+
+  /** 审核状态。 1-审核中；2-审核驳回 */
+  @JsonProperty("audit_state")
+  private Integer auditState;
+
+  /** 审核结果描述。audit_state为驳回时有值。 */
+  @JsonProperty("audit_desc")
+  private String auditDesc;
+
+  /** 精选展示位申请明细 */
+  @JsonProperty("banner")
+  private BannerItem banner;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerApplyInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerApplyInfo.java
new file mode 100644
index 0000000000..651c5c76fe
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerApplyInfo.java
@@ -0,0 +1,35 @@
+package me.chanjar.weixin.channel.bean.home.banner;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.List;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 精选展示位申请信息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class BannerApplyInfo implements Serializable {
+
+  private static final long serialVersionUID = 72190625450999960L;
+
+  /** 申请编号 */
+  @JsonProperty("apply_id")
+  private Integer applyId;
+
+  /** 申请状态 1-审核中；2-审核驳回 */
+  @JsonProperty("state")
+  private Integer state;
+
+  /** 展示位的展示样式 1-小图模式；2-大图模式 */
+  @JsonProperty("scale")
+  private Integer scale;
+
+  /** 精选展示位申请明细 */
+  @JsonProperty("banner")
+  private List<BannerApplyDetail> banner;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerApplyParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerApplyParam.java
new file mode 100644
index 0000000000..04c7abc2a7
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerApplyParam.java
@@ -0,0 +1,28 @@
+package me.chanjar.weixin.channel.bean.home.banner;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 精选展示位申请参数
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@JsonInclude(Include.NON_NULL)
+public class BannerApplyParam implements Serializable {
+
+  private static final long serialVersionUID = 9083668032979490150L;
+
+  /** banner */
+  @JsonProperty("banner")
+  private BannerInfo banner;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerApplyResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerApplyResponse.java
new file mode 100644
index 0000000000..f83f119d13
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerApplyResponse.java
@@ -0,0 +1,25 @@
+package me.chanjar.weixin.channel.bean.home.banner;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 提交精选展位申请 结果
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class BannerApplyResponse extends WxChannelBaseResponse {
+
+  private static final long serialVersionUID = -2194587734444499201L;
+
+  /** 申请编号 */
+  @JsonProperty("apply_id")
+  private Integer applyId;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerGetResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerGetResponse.java
new file mode 100644
index 0000000000..1c6a920636
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerGetResponse.java
@@ -0,0 +1,28 @@
+package me.chanjar.weixin.channel.bean.home.banner;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 精选展位返回结果
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class BannerGetResponse extends WxChannelBaseResponse {
+
+  private static final long serialVersionUID = -1563254921362215934L;
+
+  /** 当前生效的展示位 */
+  @JsonProperty("banner")
+  private BannerInfo banner;
+
+  /** 最近一次流程中的申请。不返回已生效或已撤销的申请 */
+  @JsonProperty("apply")
+  private BannerApplyInfo apply;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerInfo.java
new file mode 100644
index 0000000000..24b501a97d
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerInfo.java
@@ -0,0 +1,31 @@
+package me.chanjar.weixin.channel.bean.home.banner;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.List;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 精选展示位
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@JsonInclude(Include.NON_NULL)
+public class BannerInfo implements Serializable {
+
+  private static final long serialVersionUID = -2003175482038217418L;
+
+  /** 展示位的展示样式 1-小图模式；2-大图模式 */
+  @JsonProperty("scale")
+  private Integer scale;
+
+  /** 精选展示位明细 */
+  @JsonProperty("banner")
+  private List<BannerItem> banner;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerItem.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerItem.java
new file mode 100644
index 0000000000..9a5cad9649
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerItem.java
@@ -0,0 +1,41 @@
+package me.chanjar.weixin.channel.bean.home.banner;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 精选展示位明细
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@JsonInclude(Include.NON_NULL)
+public class BannerItem implements Serializable {
+
+  private static final long serialVersionUID = 6982412458700854481L;
+
+  /** 展示位类型 1-商品 3-视频号 4-公众号 {@link me.chanjar.weixin.channel.enums.BannerType} */
+  @JsonProperty("type")
+  private Integer type;
+
+  /** 展示位信息 */
+  @JsonProperty("banner")
+  private BannerItemDetail banner;
+
+  /** 商品 */
+  @JsonProperty("product")
+  private BannerItemProduct product;
+
+  /** 视频号 */
+  @JsonProperty("finder")
+  private BannerItemFinder finder;
+
+  /** 公众号 */
+  @JsonProperty("official_account")
+  private BannerItemOfficialAccount officialAccount;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerItemDetail.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerItemDetail.java
new file mode 100644
index 0000000000..b5cfb4a38c
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerItemDetail.java
@@ -0,0 +1,33 @@
+package me.chanjar.weixin.channel.bean.home.banner;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 精选展示位明细中的明细
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@JsonInclude(Include.NON_NULL)
+public class BannerItemDetail implements Serializable {
+
+  private static final long serialVersionUID = 5975434996207526173L;
+
+  /** 图片url */
+  @JsonProperty("img_url")
+  private String imgUrl;
+
+  /** 标题 */
+  @JsonProperty("title")
+  private String title;
+
+  /** 描述 */
+  @JsonProperty("description")
+  private String description;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerItemFinder.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerItemFinder.java
new file mode 100644
index 0000000000..735a2038da
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerItemFinder.java
@@ -0,0 +1,29 @@
+package me.chanjar.weixin.channel.bean.home.banner;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 精选展示位明细中的视频号数据
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@JsonInclude(Include.NON_NULL)
+public class BannerItemFinder implements Serializable {
+
+  private static final long serialVersionUID = -7397790079913284012L;
+
+  /** 视频号ID */
+  @JsonProperty("finder_user_name")
+  private String finderUserName;
+
+  /** 视频号视频的唯一标识 */
+  @JsonProperty("feed_id")
+  private String feedId;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerItemOfficialAccount.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerItemOfficialAccount.java
new file mode 100644
index 0000000000..0488829642
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerItemOfficialAccount.java
@@ -0,0 +1,25 @@
+package me.chanjar.weixin.channel.bean.home.banner;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 精选展示位明细中的公众号数据
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@JsonInclude(Include.NON_NULL)
+public class BannerItemOfficialAccount implements Serializable {
+
+  private static final long serialVersionUID = -5596947592282082891L;
+
+  /** 公众号文章url */
+  @JsonProperty("url")
+  private String url;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerItemProduct.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerItemProduct.java
new file mode 100644
index 0000000000..87a51823f0
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/banner/BannerItemProduct.java
@@ -0,0 +1,25 @@
+package me.chanjar.weixin.channel.bean.home.banner;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 精选展示位明细中的商品
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@JsonInclude(Include.NON_NULL)
+public class BannerItemProduct implements Serializable {
+
+  private static final long serialVersionUID = 8034487065591522594L;
+
+  /** 商品id */
+  @JsonProperty("product_id")
+  private Long productId;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/CatTreeNode.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/CatTreeNode.java
new file mode 100644
index 0000000000..c545b8637f
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/CatTreeNode.java
@@ -0,0 +1,32 @@
+package me.chanjar.weixin.channel.bean.home.tree;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 主页分类信息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class CatTreeNode implements Serializable {
+
+  private static final long serialVersionUID = 3154219180098003510L;
+
+  /** 分类id */
+  @JsonProperty("id")
+  private Integer id;
+
+  /** 分类名字 */
+  @JsonProperty("name")
+  private String name;
+
+  /** 是否在用户端展示该分类。1为是，0为否 */
+  @JsonProperty("is_displayed")
+  private Boolean displayed;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/LevelTreeInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/LevelTreeInfo.java
new file mode 100644
index 0000000000..104588202e
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/LevelTreeInfo.java
@@ -0,0 +1,24 @@
+package me.chanjar.weixin.channel.bean.home.tree;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.List;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 分类信息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class LevelTreeInfo implements Serializable {
+
+  /** 一级分类 */
+  @JsonProperty("level_1")
+  private List<OneLevelTreeNode> level1;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/OneLevelTreeNode.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/OneLevelTreeNode.java
new file mode 100644
index 0000000000..76499c86e7
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/OneLevelTreeNode.java
@@ -0,0 +1,25 @@
+package me.chanjar.weixin.channel.bean.home.tree;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.List;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+/**
+ * 一级分类
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class OneLevelTreeNode extends CatTreeNode {
+
+  /** 二级分类 */
+  @JsonProperty("level_2")
+  private List<CatTreeNode> level2;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeAuditResult.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeAuditResult.java
new file mode 100644
index 0000000000..b85dda46dd
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeAuditResult.java
@@ -0,0 +1,27 @@
+package me.chanjar.weixin.channel.bean.home.tree;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.List;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 展示在店铺主页的商品分类
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class TreeAuditResult implements Serializable {
+
+  private static final long serialVersionUID = 8142657614529852121L;
+
+  /** 版本号。设置分类树的接口会用到 */
+  @JsonProperty("version")
+  private Integer version;
+
+  /** 展示在店铺主页的商品分类 */
+  @JsonProperty("audit_results")
+  private List<TreeAuditResultDetail> auditResults;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeAuditResultDetail.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeAuditResultDetail.java
new file mode 100644
index 0000000000..92df865061
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeAuditResultDetail.java
@@ -0,0 +1,27 @@
+package me.chanjar.weixin.channel.bean.home.tree;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 分类审核结果
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class TreeAuditResultDetail implements Serializable {
+
+  private static final long serialVersionUID = -6085892397971684732L;
+
+  /** 该分类ID的审核结果 */
+  @JsonProperty("level_id")
+  private Integer level_id;
+
+  /** 审核结果枚举。1:不通过；2:通过 */
+  @JsonProperty("result_code")
+  private Integer result_code;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeProductEditInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeProductEditInfo.java
new file mode 100644
index 0000000000..d7dd831c3d
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeProductEditInfo.java
@@ -0,0 +1,33 @@
+package me.chanjar.weixin.channel.bean.home.tree;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.List;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 添加/删除分类关联的商品 参数
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TreeProductEditInfo implements Serializable {
+
+  private static final long serialVersionUID = -5596947592282082891L;
+
+  /** 一级分类id */
+  @JsonProperty("level_1_id")
+  private Integer level1Id;
+
+  /** 二级分类id */
+  @JsonProperty("level_2_id")
+  private Integer level2Id;
+
+  /** 商品id列表 */
+  @JsonProperty("product_ids")
+  private List<Long> productIds;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeProductEditParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeProductEditParam.java
new file mode 100644
index 0000000000..fb42162ca6
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeProductEditParam.java
@@ -0,0 +1,25 @@
+package me.chanjar.weixin.channel.bean.home.tree;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 添加/删除分类关联的商品 参数
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TreeProductEditParam implements Serializable {
+
+  private static final long serialVersionUID = -4906016235749892703L;
+
+  /** 参数 */
+  @JsonProperty("req")
+  private TreeProductEditInfo req;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeProductListInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeProductListInfo.java
new file mode 100644
index 0000000000..a37e784d14
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeProductListInfo.java
@@ -0,0 +1,36 @@
+package me.chanjar.weixin.channel.bean.home.tree;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 查询分类关联的商品 参数
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TreeProductListInfo implements Serializable {
+
+  private static final long serialVersionUID = 2774682583380930076L;
+
+  /** 一级分类id */
+  @JsonProperty("level_1_id")
+  private Integer level1Id;
+
+  /** 二级分类id */
+  @JsonProperty("level_2_id")
+  private Integer level2Id;
+
+  /** 分页大小 */
+  @JsonProperty("page_size")
+  private Integer pageSize;
+
+  /** 从头拉取填空。翻页拉取的话填resp返回的值 */
+  @JsonProperty("page_context")
+  private String pageContext;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeProductListParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeProductListParam.java
new file mode 100644
index 0000000000..7bb6a700e2
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeProductListParam.java
@@ -0,0 +1,24 @@
+package me.chanjar.weixin.channel.bean.home.tree;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 查询分类关联的商品 参数
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TreeProductListParam implements Serializable {
+
+  private static final long serialVersionUID = -8444106841479328711L;
+
+  /** 参数 */
+  @JsonProperty("req")
+  private TreeProductListInfo req;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeProductListResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeProductListResponse.java
new file mode 100644
index 0000000000..ed0081d70c
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeProductListResponse.java
@@ -0,0 +1,24 @@
+package me.chanjar.weixin.channel.bean.home.tree;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 资金流水响应
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class TreeProductListResponse extends WxChannelBaseResponse {
+
+  private static final long serialVersionUID = 4566848209585635054L;
+
+  /** 结果 */
+  @JsonProperty("resp")
+  private TreeProductListResult resp;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeProductListResult.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeProductListResult.java
new file mode 100644
index 0000000000..6e0fdfea6c
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeProductListResult.java
@@ -0,0 +1,31 @@
+package me.chanjar.weixin.channel.bean.home.tree;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.List;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 资金流水响应 结果
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class TreeProductListResult implements Serializable {
+
+  private static final long serialVersionUID = 4566848209585635054L;
+
+  /** 关联的商品ID。如果返回为空，返回翻页到底了 */
+  @JsonProperty("product_ids")
+  private List<Long> productIds;
+
+  /** 总条数 */
+  @JsonProperty("total_count")
+  private Integer totalCount;
+
+  /** 拉取下一页的话，需要把这个值填到req的page_context里面 */
+  @JsonProperty("page_context")
+  private String pageContext;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeShowGetResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeShowGetResponse.java
new file mode 100644
index 0000000000..f3784c48fb
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeShowGetResponse.java
@@ -0,0 +1,20 @@
+package me.chanjar.weixin.channel.bean.home.tree;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class TreeShowGetResponse extends WxChannelBaseResponse {
+
+  /** resp */
+  @JsonProperty("resp")
+  private TreeShowInfo resp;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeShowInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeShowInfo.java
new file mode 100644
index 0000000000..09da2c5b0c
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeShowInfo.java
@@ -0,0 +1,45 @@
+package me.chanjar.weixin.channel.bean.home.tree;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.List;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 分类展示信息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TreeShowInfo implements Serializable {
+
+  /** 分类树 */
+  @JsonProperty("tree")
+  private LevelTreeInfo tree;
+
+  /** 版本号。通过获取商品分类树或者本接口得到 */
+  @JsonProperty("version")
+  private Integer version;
+
+  /** 表示有哪一些分类ID清空关联得商品,如果不清空,那么分类ID和商品得关联关系会一直存在。如果是一级分类，就填"1"。如果是二级分类，就填"1.2"。 */
+  @JsonProperty("classification_id_deleted")
+  private List<String> classificationIdDeleted;
+
+  // 一些自定义的方法
+
+  /**
+   * 创建Tree节点
+   *
+   * @return Tree节点
+   */
+  protected LevelTreeInfo createTree() {
+    if (tree == null) {
+      tree = new LevelTreeInfo();
+    }
+    return tree;
+  }
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeShowParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeShowParam.java
new file mode 100644
index 0000000000..7277c528f4
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeShowParam.java
@@ -0,0 +1,24 @@
+package me.chanjar.weixin.channel.bean.home.tree;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 设置展示在店铺主页的商品分类 参数
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TreeShowParam implements Serializable {
+
+  private static final long serialVersionUID = -1577647561992899360L;
+
+  /** 分类信息 */
+  @JsonProperty("req")
+  private TreeShowInfo req;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeShowSetResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeShowSetResponse.java
new file mode 100644
index 0000000000..ad65332644
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/tree/TreeShowSetResponse.java
@@ -0,0 +1,20 @@
+package me.chanjar.weixin.channel.bean.home.tree;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class TreeShowSetResponse extends WxChannelBaseResponse {
+
+  /** resp */
+  @JsonProperty("resp")
+  private TreeAuditResult resp;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/window/WindowProductIndexParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/window/WindowProductIndexParam.java
new file mode 100644
index 0000000000..fcc16bd0f6
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/window/WindowProductIndexParam.java
@@ -0,0 +1,28 @@
+package me.chanjar.weixin.channel.bean.home.window;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 主页商品排序参数
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class WindowProductIndexParam implements Serializable {
+
+  private static final long serialVersionUID = 1370480140179330908L;
+
+  /** 商品id */
+  @JsonProperty("product_id")
+  private String productId;
+
+  /** 商品重新排序后的新序号，最大移动步长为500（即新序号与当前序号的距离小于500） */
+  @JsonProperty("index_num")
+  private Integer indexNum;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/window/WindowProductListParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/window/WindowProductListParam.java
new file mode 100644
index 0000000000..9245df9887
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/window/WindowProductListParam.java
@@ -0,0 +1,26 @@
+package me.chanjar.weixin.channel.bean.home.window;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 获取主页展示商品列表 参数
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class WindowProductListParam implements Serializable {
+
+  /** 每页数量（默认10，不超过30） */
+  @JsonProperty("page_size")
+  private Integer pageSize;
+
+  /** 由上次请求返回，记录翻页的上下文。传入时会从上次返回的结果往后翻一页，不传默认获取第一页数据。 */
+  @JsonProperty("next_key")
+  private String nextKey;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/window/WindowProductSetting.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/window/WindowProductSetting.java
new file mode 100644
index 0000000000..725470b912
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/window/WindowProductSetting.java
@@ -0,0 +1,34 @@
+package me.chanjar.weixin.channel.bean.home.window;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 主页商品配置 返回结果 / 设置请求参数
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class WindowProductSetting implements Serializable {
+
+  private static final long serialVersionUID = -5931781905709862287L;
+
+  /** 商品id */
+  @JsonProperty("product_id")
+  private String productId;
+
+  /** 是否隐藏，设置为隐藏的商品只在首页不可见，并不代表下架。 */
+  @JsonProperty("is_set_hide")
+  private Integer setHide;
+
+  /** 是否置顶 */
+  @JsonProperty("is_set_top")
+  private Integer setTop;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/window/WindowProductSettingResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/window/WindowProductSettingResponse.java
new file mode 100644
index 0000000000..495910e37d
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/home/window/WindowProductSettingResponse.java
@@ -0,0 +1,33 @@
+package me.chanjar.weixin.channel.bean.home.window;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.List;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 主页商品配置列表
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class WindowProductSettingResponse extends WxChannelBaseResponse {
+
+  private static final long serialVersionUID = 1L;
+
+  /** 商品信息 */
+  @JsonProperty("products")
+  private List<WindowProductSetting> products;
+
+  /** 本次翻页的上下文，用于请求下一页 */
+  @JsonProperty("next_key")
+  private String nextKey;
+
+  /** 商品总数 */
+  @JsonProperty("total_num")
+  private Integer totalNum;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/league/promoter/PromoterListResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/league/promoter/PromoterListResponse.java
index c193550369..f7c7298c03 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/league/promoter/PromoterListResponse.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/league/promoter/PromoterListResponse.java
@@ -18,11 +18,19 @@
 public class PromoterListResponse extends WxChannelBaseResponse {
 
   private static final long serialVersionUID = 1411870432999885996L;
-  /** 达人finder_id列表 */
+  /** 达人finder_id列表，待废除后续以promoter_ids为准 */
   @JsonProperty("finder_ids")
   private List<String> finderIds;
 
   /** 达人总数 */
   @JsonProperty("total_num")
   private Integer totalNum;
+
+  /** 后面是否还有（true: 还有内容; false: 已结束）*/
+  @JsonProperty("continue_flag")
+  private Boolean continueFlag;
+
+  /** 达人带货id列表 */
+  @JsonProperty("promoter_ids")
+  private List<String> promoterIds;
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/league/supplier/SupplierFlowListResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/league/supplier/SupplierFlowListResponse.java
index 468985fe3e..d4a04af981 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/league/supplier/SupplierFlowListResponse.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/league/supplier/SupplierFlowListResponse.java
@@ -9,8 +9,7 @@
 /**
  * 资金流水列表 响应
  *
- * @author LiXiZe
- * @since 2023-04-16
+ * @author <a href="https://github.com/lixize">Zeyes</a>
  */
 @Data
 @NoArgsConstructor
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/message/product/SpuStockMessage.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/message/product/SpuStockMessage.java
new file mode 100644
index 0000000000..96feac5a4a
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/message/product/SpuStockMessage.java
@@ -0,0 +1,88 @@
+package me.chanjar.weixin.channel.bean.message.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
+import java.util.Map;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.message.WxChannelMessage;
+
+/**
+ * SPU库存不足消息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@JacksonXmlRootElement(localName = "xml")
+public class SpuStockMessage extends WxChannelMessage {
+
+  private static final long serialVersionUID = 2250860804161527363L;
+
+  /** 商品id */
+  @JsonProperty("product_id")
+  @JacksonXmlProperty(localName = "product_id")
+  private String productId;
+
+  /** 平台商品id */
+  @JsonProperty("sku_id")
+  @JacksonXmlProperty(localName = "sku_id")
+  private String skuId;
+
+  /** 剩余库存：当前实时库存数量 */
+  @JsonProperty("remaining_stock_amount")
+  @JacksonXmlProperty(localName = "remaining_stock_amount")
+  private Long remainingStockAmount;
+
+  /** 未发放的预存code数【该字段对code_source_type=2的团购优惠生效，其他类型该字段值为0】 */
+  @JsonProperty("remaining_code_amount")
+  @JacksonXmlProperty(localName = "remaining_code_amount")
+  private Long remainingCodeAmount;
+
+  /** ChannelsEcStockNoEnough */
+  @JsonProperty("channels_ec_stock_no_enough")
+  @JacksonXmlProperty(localName = "channels_ec_stock_no_enough")
+  private void stockNoEnough(Map<String, Object> map) {
+    this.unpackNameFromNestedObject(map);
+  }
+
+  /**
+   * 从嵌套对象中解析字段
+   *
+   * @param map 嵌套对象
+   */
+  protected void unpackNameFromNestedObject(Map<String, Object> map) {
+    if (map == null) {
+      return;
+    }
+    Object obj = null;
+    obj = map.get("product_id");
+    if (obj != null) {
+      this.productId = (obj instanceof String ? (String) obj : String.valueOf(obj));
+    }
+    obj = map.get("sku_id");
+    if (obj != null) {
+      this.skuId = (obj instanceof String ? (String) obj : String.valueOf(obj));
+    }
+
+    obj = map.get("remaining_stock_amount");
+    if (obj != null) {
+      if (obj instanceof Number) {
+        this.remainingStockAmount = ((Number) obj).longValue();
+      } else if (obj instanceof String) {
+        this.remainingStockAmount = Long.parseLong((String) obj);
+      }
+    }
+    obj = map.get("remaining_code_amount");
+    if (obj != null) {
+      if (obj instanceof Number) {
+        this.remainingCodeAmount = ((Number) obj).longValue();
+      } else if (obj instanceof String) {
+        this.remainingCodeAmount = Long.parseLong((String) obj);
+      }
+    }
+  }
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/message/store/CloseStoreMessage.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/message/store/CloseStoreMessage.java
new file mode 100644
index 0000000000..2a43483354
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/message/store/CloseStoreMessage.java
@@ -0,0 +1,38 @@
+package me.chanjar.weixin.channel.bean.message.store;
+
+/**
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.message.WxChannelMessage;
+
+/**
+ * 小店注销消息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@JacksonXmlRootElement(localName = "xml")
+public class CloseStoreMessage extends WxChannelMessage {
+
+  private static final long serialVersionUID = 7619787772418774020L;
+
+  /** appid */
+  @JsonProperty("appid")
+  @JacksonXmlProperty(localName = "appid")
+  private String appid;
+
+  /** Unix时间戳，即格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数 */
+  @JsonProperty("close_timestamp")
+  @JacksonXmlProperty(localName = "close_timestamp")
+  private Long closeTimestamp;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/message/store/NicknameUpdateMessage.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/message/store/NicknameUpdateMessage.java
new file mode 100644
index 0000000000..e6665497e0
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/message/store/NicknameUpdateMessage.java
@@ -0,0 +1,43 @@
+package me.chanjar.weixin.channel.bean.message.store;
+
+/**
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.message.WxChannelMessage;
+
+/**
+ * 小店修改名称消息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@JacksonXmlRootElement(localName = "xml")
+public class NicknameUpdateMessage extends WxChannelMessage {
+
+  private static final long serialVersionUID = 7619787772418774020L;
+
+  /** appid */
+  @JsonProperty("appid")
+  @JacksonXmlProperty(localName = "appid")
+  private String appid;
+
+  /** 小店旧昵称 */
+  @JsonProperty("old_nickname")
+  @JacksonXmlProperty(localName = "old_nickname")
+  private String oldNickname;
+
+  /** 小店新昵称 */
+  @JsonProperty("new_nickname")
+  @JacksonXmlProperty(localName = "new_nickname")
+  private String newNickname;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/message/voucher/VoucherInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/message/voucher/VoucherInfo.java
new file mode 100644
index 0000000000..1b5a926205
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/message/voucher/VoucherInfo.java
@@ -0,0 +1,106 @@
+package me.chanjar.weixin.channel.bean.message.voucher;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class VoucherInfo implements Serializable {
+  private static final long serialVersionUID = 6007964849358969438L;
+
+  /** 券code */
+  @JsonProperty("code")
+  @JacksonXmlProperty(localName = "code")
+  private String code;
+
+  /** 劵码类型，1商户实时code 2户预存 3平台生成 */
+  @JsonProperty("code_type")
+  @JacksonXmlProperty(localName = "code_type")
+  private Integer codeType;
+
+  /** 券状态 */
+  @JsonProperty("status")
+  @JacksonXmlProperty(localName = "status")
+  private Integer status;
+
+  /** 发放时间，时间戳 */
+  @JsonProperty("send_time")
+  @JacksonXmlProperty(localName = "send_time")
+  private Long sendTime;
+
+  /** 最近更新时间，时间戳 */
+  @JsonProperty("update_time")
+  @JacksonXmlProperty(localName = "update_time")
+  private Long updateTime;
+
+  /** 核销生效时间，时间戳 */
+  @JsonProperty("start_time")
+  @JacksonXmlProperty(localName = "start_time")
+  private Long startTime;
+
+  /** 核销结束时间，时间戳 */
+  @JsonProperty("end_time")
+  @JacksonXmlProperty(localName = "end_time")
+  private Long endTime;
+
+  /** 核销时间，时间戳。次卡时不返回此字段 */
+  @JsonProperty("consume_time")
+  @JacksonXmlProperty(localName = "consume_time")
+  private Long consumeTime;
+
+  /** 退券时间，时间戳。次卡时不返回此字段 */
+  @JsonProperty("refund_time")
+  @JacksonXmlProperty(localName = "refund_time")
+  private Long refundTime;
+
+  /** 核销门店名称 */
+  @JsonProperty("consume_store_name")
+  @JacksonXmlProperty(localName = "consume_store_name")
+  private String consumeStoreName;
+
+  /**  */
+  @JsonProperty("voucher_type")
+  @JacksonXmlProperty(localName = "voucher_type")
+  private Integer voucherType;
+
+  /** 券的售卖价格（分） */
+  @JsonProperty("voucher_buy_amount")
+  @JacksonXmlProperty(localName = "voucher_buy_amount")
+  private Integer voucherBuyAmount;
+
+  /** 券市场金额（分） */
+  @JsonProperty("voucher_actual_amount")
+  @JacksonXmlProperty(localName = "voucher_actual_amount")
+  private Integer voucherActualAmount;
+
+  /** 用户手机号 */
+  @JsonProperty("telphone_no")
+  @JacksonXmlProperty(localName = "telphone_no")
+  private String telPhoneNo;
+
+  /** 商品id */
+  @JsonProperty("product_id")
+  @JacksonXmlProperty(localName = "product_id")
+  private String productId;
+
+  /** 商品下的skuId */
+  @JsonProperty("sku_id")
+  @JacksonXmlProperty(localName = "sku_id")
+  private String skuId;
+
+  /** 购买券的订单id */
+  @JsonProperty("order_id")
+  @JacksonXmlProperty(localName = "order_id")
+  private String orderId;
+
+  /** 用户在商家品牌appid下的openid */
+  @JsonProperty("openid")
+  @JacksonXmlProperty(localName = "openid")
+  private String openId;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/message/voucher/VoucherMessage.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/message/voucher/VoucherMessage.java
new file mode 100644
index 0000000000..941828969d
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/message/voucher/VoucherMessage.java
@@ -0,0 +1,29 @@
+package me.chanjar.weixin.channel.bean.message.voucher;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
+import java.util.List;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.message.WxChannelMessage;
+
+/**
+ * 发放团购优惠成功消息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@JacksonXmlRootElement(localName = "xml")
+public class VoucherMessage extends WxChannelMessage {
+
+  private static final long serialVersionUID = 975858675917036089L;
+
+  /** 发放团购优惠成功消息 */
+  @JsonProperty("voucher_list")
+  @JacksonXmlProperty(localName = "voucher_list")
+  private List<VoucherInfo> voucherInfo;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/DecodeAddressInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/DecodeAddressInfo.java
new file mode 100644
index 0000000000..3aa6622eeb
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/DecodeAddressInfo.java
@@ -0,0 +1,22 @@
+package me.chanjar.weixin.channel.bean.order;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.AddressInfo;
+
+/**
+ * 解码地址数据
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class DecodeAddressInfo extends AddressInfo {
+
+  /** 虚拟发货订单联系方式，在发货方式为无需快递(deliver_method=1)时返回 */
+  @JsonProperty("virtual_order_tel_number")
+  private String virtualOrderTelNumber;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/DecodeSensitiveInfoResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/DecodeSensitiveInfoResponse.java
new file mode 100644
index 0000000000..c0431a8fd6
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/DecodeSensitiveInfoResponse.java
@@ -0,0 +1,28 @@
+package me.chanjar.weixin.channel.bean.order;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 解码订单包含的敏感数据响应
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class DecodeSensitiveInfoResponse extends WxChannelBaseResponse {
+
+  private static final long serialVersionUID = 935829924760021624L;
+
+  /** 收货信息 */
+  @JsonProperty("address_info")
+  private DecodeAddressInfo addressInfo;
+
+  /** 虚拟号信息 */
+  @JsonProperty("virtual_number_info")
+  private VirtualNumberInfo virtualNumberInfo;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderAgentInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderAgentInfo.java
new file mode 100644
index 0000000000..548e36dd49
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderAgentInfo.java
@@ -0,0 +1,30 @@
+package me.chanjar.weixin.channel.bean.order;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 授权账号信息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class OrderAgentInfo implements Serializable {
+
+  private static final long serialVersionUID = 6396067079343033841L;
+
+  /**
+   * 授权视频号id
+   */
+  @JsonProperty("agent_finder_id")
+  private String agentFinderId;
+
+  /**
+   * 授权视频号昵称
+   */
+  @JsonProperty("agent_finder_nickname")
+  private String agentFinderNickname;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderCommissionInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderCommissionInfo.java
index 78e391e774..f3cab1f4bf 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderCommissionInfo.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderCommissionInfo.java
@@ -42,4 +42,8 @@ public class OrderCommissionInfo implements Serializable {
   /** 达人openfinderid */
   @JsonProperty("openfinderid")
   private String openFinderId;
+
+  /** 新带货平台 id */
+  @JsonProperty("talent_id")
+  private String talentId;
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderCustomInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderCustomInfo.java
new file mode 100644
index 0000000000..88981c6ccc
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderCustomInfo.java
@@ -0,0 +1,33 @@
+package me.chanjar.weixin.channel.bean.order;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 商品定制信息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class OrderCustomInfo implements Serializable {
+  private static final long serialVersionUID = 6681266835402157651L;
+
+  /** 定制图片，custom_type=2时返回 */
+  @JsonProperty("custom_img_url")
+  private String customImgUrl;
+
+  /** 定制文字，custom_type=1时返回 */
+  @JsonProperty("custom_word")
+  private String customWord;
+
+  /** 定制类型，枚举值请参考CustomType枚举 */
+  @JsonProperty("custom_type")
+  private Integer customType;
+
+  /** 定制预览图片，开启了定制预览时返回 */
+  @JsonProperty("custom_preview_img_url")
+  private String customPreviewImgUrl;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderDeliveryInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderDeliveryInfo.java
index 9f3d72feac..ebe6bb8dc2 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderDeliveryInfo.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderDeliveryInfo.java
@@ -44,4 +44,16 @@ public class OrderDeliveryInfo implements Serializable {
   @JsonProperty("ewaybill_order_code")
   private String ewaybillOrderCode;
 
+  /** 订单质检类型 2生鲜类质检 1珠宝玉石类质检 0不需要；不传递本字段表示不需要 */
+  @JsonProperty("quality_inspect_type")
+  private String qualityInspectType;
+
+  /** 质检信息 */
+  @JsonProperty("quality_inspect_info")
+  private QualityInsepctInfo qualityInspectInfo;
+
+  /** 虚拟商品充值账户信息 */
+  @JsonProperty("recharge_info")
+  private RechargeInfo rechargeInfo;
+
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderDetailInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderDetailInfo.java
index 8a17140cc1..4d96023be1 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderDetailInfo.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderDetailInfo.java
@@ -56,4 +56,23 @@ public class OrderDetailInfo implements Serializable {
   @JsonProperty("sku_sharer_infos")
   private List<OrderSkuShareInfo> skuSharerInfos;
 
+  /** 授权账号信息 */
+  @JsonProperty("agent_info")
+  private OrderAgentInfo agentInfo;
+
+  /** 订单来源信息 */
+  @JsonProperty("source_infos")
+  private List<OrderSourceInfo> sourceInfos;
+
+  /** 订单退款信息 */
+  @JsonProperty("refund_info")
+  private OrderSourceInfo refundInfo;
+
+  /** 订单代写商品信息 */
+  @JsonProperty("greeting_card_info")
+  private OrderGreetingCardInfo greetingCardInfo;
+
+  /** 商品定制信息 */
+  @JsonProperty("custom_info")
+  private OrderCustomInfo customInfo;
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderGreetingCardInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderGreetingCardInfo.java
new file mode 100644
index 0000000000..6b0c37033f
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderGreetingCardInfo.java
@@ -0,0 +1,29 @@
+package me.chanjar.weixin.channel.bean.order;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 订单商品贺卡信息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class OrderGreetingCardInfo implements Serializable {
+  private static final long serialVersionUID = -6391443179945240242L;
+
+  /** 贺卡落款，用户选填 */
+  @JsonProperty("giver_name")
+  private String giverName;
+
+  /** 贺卡称谓，用户选填 */
+  @JsonProperty("receiver_name")
+  private String receiverName;
+
+  /** 贺卡内容，用户必填 */
+  @JsonProperty("greeting_message")
+  private String greetingMessage;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderInfo.java
index 894b36f7af..00222d8487 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderInfo.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderInfo.java
@@ -39,6 +39,26 @@ public class OrderInfo implements Serializable {
   @JsonProperty("aftersale_detail")
   protected AfterSaleDetail afterSaleDetail;
 
+  /** 是否为礼物订单 */
+  @JsonProperty("is_present")
+  private Boolean present;
+
+  /** 礼物订单ID */
+  @JsonProperty("present_order_id_str")
+  private String presentOrderId;
+
+  /** 礼物订单留言 */
+  @JsonProperty("present_note")
+  private String presentNote;
+
+  /** 礼物订单赠送者openid */
+  @JsonProperty("present_giver_openid")
+  private String presentGiverOpenid;
+
+  /** 礼物订单赠送者unionid */
+  @JsonProperty("present_giver_unionid")
+  private String presentGiverUnionid;
+
   /** 创建时间 秒级时间戳 */
   @JsonProperty("create_time")
   protected Integer createTime;
@@ -46,5 +66,4 @@ public class OrderInfo implements Serializable {
   /** 更新时间 秒级时间戳 */
   @JsonProperty("update_time")
   protected Integer updateTime;
-
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderInfoParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderInfoParam.java
new file mode 100644
index 0000000000..e7a8c9a2b8
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderInfoParam.java
@@ -0,0 +1,31 @@
+package me.chanjar.weixin.channel.bean.order;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 获取订单详情参数
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class OrderInfoParam implements Serializable {
+
+  private static final long serialVersionUID = 42L;
+
+  /** 订单ID */
+  @JsonProperty("order_id")
+  private String orderId;
+
+  /**
+   * 用于商家提前测试订单脱敏效果，如果传true，即对订单进行脱敏，后期会默认对所有订单脱敏
+   */
+  @JsonProperty("encode_sensitive_info")
+  private Boolean encodeSensitiveInfo;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderPriceInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderPriceInfo.java
index 64e6690a66..cad435df2b 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderPriceInfo.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderPriceInfo.java
@@ -1,10 +1,11 @@
 package me.chanjar.weixin.channel.bean.order;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
-import java.io.Serializable;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import java.io.Serializable;
+
 /**
  * 商店订单价格信息
  *
@@ -13,54 +14,97 @@
 @Data
 @NoArgsConstructor
 public class OrderPriceInfo implements Serializable {
-
   private static final long serialVersionUID = 5216506688949493432L;
-  /** 商品总价，单位为分 */
+
+  /**
+   * 商品总价，单位为分
+   */
   @JsonProperty("product_price")
   private Integer productPrice;
 
-  /** 订单金额，单位为分 */
+  /**
+   * 订单金额，单位为分
+   */
   @JsonProperty("order_price")
   private Integer orderPrice;
 
-  /** 运费，单位为分 */
+  /**
+   * 运费，单位为分
+   */
   @JsonProperty("freight")
   private Integer freight;
 
-  /** 优惠金额，单位为分 */
+  /**
+   * 优惠金额，单位为分
+   */
   @JsonProperty("discounted_price")
   private Integer discountedPrice;
 
-  /** 是否有优惠 */
+  /**
+   * 是否有优惠
+   */
   @JsonProperty("is_discounted")
   private Boolean isDiscounted;
 
-  /** 订单原始价格，单位为分 */
+  /**
+   * 订单原始价格，单位为分
+   */
   @JsonProperty("original_order_price")
   private Integer originalOrderPrice;
 
-  /** 商品预估价格，单位为分 */
+  /**
+   * 商品预估价格，单位为分
+   */
   @JsonProperty("estimate_product_price")
   private Integer estimateProductPrice;
 
-  /** 改价后降低金额，单位为分 */
+  /**
+   * 改价后降低金额，单位为分
+   */
   @JsonProperty("change_down_price")
   private Integer changeDownPrice;
 
-  /** 改价后运费，单位为分 */
+  /**
+   * 改价后运费，单位为分
+   */
   @JsonProperty("change_freight")
   private Integer changeFreight;
 
-  /** 是否修改运费 */
+  /**
+   * 是否修改运费
+   */
   @JsonProperty("is_change_freight")
   private Boolean changeFreighted;
 
-  /** 是否使用了会员积分抵扣 */
+  /**
+   * 是否使用了会员积分抵扣
+   */
   @JsonProperty("use_deduction")
   private Boolean useDeduction;
 
-  /** 会员积分抵扣金额，单位为分 */
+  /**
+   * 会员积分抵扣金额，单位为分
+   */
   @JsonProperty("deduction_price")
   private Integer deductionPrice;
 
+  /**
+   * 商家实收金额，单位为分
+   * merchant_receieve_price=original_order_price-discounted_price-deduction_price-change_down_price
+   */
+  @JsonProperty("merchant_receieve_price")
+  private Integer merchantReceivePrice;
+
+  /**
+   * 商家优惠金额，单位为分，含义同discounted_price，必填
+   */
+  @JsonProperty("merchant_discounted_price")
+  private Integer merchantDiscountedPrice;
+
+  /**
+   * 达人优惠金额，单位为分
+   */
+  @JsonProperty("finder_discounted_price")
+  private Integer finderDiscountedPrice;
+
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderProductInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderProductInfo.java
index e7edeb8912..1e49455dc4 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderProductInfo.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderProductInfo.java
@@ -168,4 +168,22 @@ public class OrderProductInfo implements Serializable {
    */
   @JsonProperty("delivery_deadline")
   private Long deliveryDeadline;
+
+  /**
+   * 商家优惠金额，单位为分
+   */
+  @JsonProperty("merchant_discounted_price")
+  private Integer merchantDiscountedPrice;
+
+  /**
+   * 商家优惠金额，单位为分
+   */
+  @JsonProperty("finder_discounted_price")
+  private Integer finderDiscountedPrice;
+
+  /**
+   * 是否赠品，非必填，赠品商品返回，1:是赠品
+   */
+  @JsonProperty("is_free_gift")
+  private Boolean freeGift;
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderRefundInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderRefundInfo.java
new file mode 100644
index 0000000000..9e3ae522f8
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderRefundInfo.java
@@ -0,0 +1,21 @@
+package me.chanjar.weixin.channel.bean.order;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 订单退款信息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class OrderRefundInfo implements Serializable {
+  private static final long serialVersionUID = -7257910073388645919L;
+
+  /** 退还运费金额，礼物订单(is_present=true)可能存在 */
+  @JsonProperty("refund_freight")
+  private Integer refundFreight;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderSearchCondition.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderSearchCondition.java
index 012b0fca49..a4c8373cec 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderSearchCondition.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderSearchCondition.java
@@ -30,12 +30,33 @@ public class OrderSearchCondition implements Serializable {
   @JsonProperty("user_name")
   private String userName;
 
-  /** 收件人电话 */
+  /**
+   * 收件人电话
+   * @deprecated 当前字段已经废弃，请勿使用，如果原本填手机后四位，可正常使用，否则接口报错
+   */
   @JsonProperty("tel_number")
+  @Deprecated
   private String telNumber;
 
+  /**
+   * 收件人电话后四位
+   */
+  @JsonProperty("tel_number_last4")
+  private String telNumberLast4;
+
   /** 选填，只搜一个订单时使用 */
   @JsonProperty("order_id")
   private String orderId;
 
+  /** 商家备注 */
+  @JsonProperty("merchant_notes")
+  private String merchantNotes;
+
+  /** 买家备注 */
+  @JsonProperty("customer_notes")
+  private String customerNotes;
+
+  /** 申请修改地址审核中 */
+  @JsonProperty("address_under_review")
+  private Boolean addressUnderReview;
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderSearchParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderSearchParam.java
index 0a9483e0d5..2f56747d19 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderSearchParam.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderSearchParam.java
@@ -25,6 +25,6 @@ public class OrderSearchParam extends StreamPageParam {
   private Integer onAfterSaleOrderExist;
 
   /** 订单状态 {@link me.chanjar.weixin.channel.enums.WxOrderStatus} */
-  @JsonProperty("on_aftersale_order_exist")
+  @JsonProperty("status")
   private Integer status;
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderSourceInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderSourceInfo.java
new file mode 100644
index 0000000000..8d5e5aaef0
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/OrderSourceInfo.java
@@ -0,0 +1,66 @@
+package me.chanjar.weixin.channel.bean.order;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 订单带货来源信息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class OrderSourceInfo implements Serializable {
+
+  private static final long serialVersionUID = 3131907659419977296L;
+
+  /**
+   * sku_id
+   */
+  @JsonProperty("sku_id")
+  private String skuId;
+
+  /**
+   * 带货账号类型，1：视频号，2：公众号，3：小程序，4：企业微信，5：带货达人，6：服务号，1000：带货机构
+   */
+  @JsonProperty("account_type")
+  private Integer accountType;
+
+  /**
+   * 带货账号id，取决于带货账号类型（分别为视频号id、公众号appid、小程序appid、企业微信id、带货达人appid、服务号appid、带货机构id）
+   */
+  @JsonProperty("account_id")
+  private String accountId;
+
+  /**
+   * 账号关联类型，0：关联账号，1：合作账号，2：授权号，100：达人带货，101：带货机构推广
+   */
+  @JsonProperty("sale_channel")
+  private Integer saleChannel;
+
+  /**
+   * 带货账号昵称
+   */
+  @JsonProperty("account_nickname")
+  private String accountNickname;
+
+  /**
+   * 带货内容类型，1：企微成员转发
+   */
+  @JsonProperty("content_type")
+  private String contentType;
+
+  /**
+   * 带货内容id，取决于带货内容类型（企微成员user_id）
+   */
+  @JsonProperty("content_id")
+  private String contentId;
+
+  /**
+   * 自营推客推广的带货机构id
+   */
+  @JsonProperty("promoter_head_supplier_id")
+  private String promoterHeadSupplierId;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/QualityInsepctInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/QualityInsepctInfo.java
new file mode 100644
index 0000000000..64c1102bb2
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/QualityInsepctInfo.java
@@ -0,0 +1,22 @@
+package me.chanjar.weixin.channel.bean.order;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 质检信息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class QualityInsepctInfo implements Serializable {
+
+  private static final long serialVersionUID = 8109819414306253475L;
+
+  /** 质检状态 */
+  @JsonProperty("inspect_status")
+  private Integer inspectStatus;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/RechargeInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/RechargeInfo.java
new file mode 100644
index 0000000000..452dd0677c
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/RechargeInfo.java
@@ -0,0 +1,28 @@
+package me.chanjar.weixin.channel.bean.order;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 虚拟商品充值账户信息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class RechargeInfo implements Serializable {
+
+  /** 虚拟商品充值账号，当account_type=qq或phone_number或mail的时候返回 */
+  @JsonProperty("account_no")
+  private String accountNo;
+
+  /** 账号充值类型，可选项: weixin(微信号),qq(qq),phone_number(电话号码),mail(邮箱) */
+  @JsonProperty("account_type")
+  private String accountType;
+
+  /** 当account_type="weixin"的时候返回 */
+  @JsonProperty("wx_openid")
+  private String wxOpenId;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/VirtualNumberInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/VirtualNumberInfo.java
new file mode 100644
index 0000000000..217908e27c
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/VirtualNumberInfo.java
@@ -0,0 +1,30 @@
+package me.chanjar.weixin.channel.bean.order;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 虚拟号信息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class VirtualNumberInfo implements Serializable {
+
+  private static final long serialVersionUID = -372834823737476644L;
+
+  /** 虚拟号 */
+  @JsonProperty("virtual_number")
+  private String virtualNumber;
+
+  /** 分机号 */
+  @JsonProperty("extension")
+  private String extension;
+
+  /** 过期时间戳 */
+  @JsonProperty("expiration")
+  private Long expiration;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/VirtualTelNumberResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/VirtualTelNumberResponse.java
new file mode 100644
index 0000000000..92f09b59ab
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/order/VirtualTelNumberResponse.java
@@ -0,0 +1,30 @@
+package me.chanjar.weixin.channel.bean.order;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 兑换虚拟号 返回结果
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class VirtualTelNumberResponse extends WxChannelBaseResponse {
+
+  /** 虚拟号码 */
+  @JsonProperty("virtual_tel_number")
+  private String virtualTelNumber;
+
+  /** 虚拟号码过期时间 */
+  @JsonProperty("virtual_tel_expire_time")
+  private Long virtualTelExpireTime;
+
+  /** 兑换虚拟号码次数 */
+  @JsonProperty("get_virtual_tel_cnt")
+  private Integer getVirtualTelCnt;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExtraServiceInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExtraServiceInfo.java
index aeaf1a8cd6..4e9559c565 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExtraServiceInfo.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ExtraServiceInfo.java
@@ -20,4 +20,20 @@ public class ExtraServiceInfo implements Serializable {
    */
   @JsonProperty("seven_day_return")
   private Integer sevenDayReturn;
+
+  /** 先用后付，0-不支持先用后付，1-支持先用后付。若店铺已开通先用后付，支持先用后付的类目商品将在上架后自动打开先用后付。 */
+  @JsonProperty("pay_after_use")
+  private Integer payAfterUse;
+
+  /** 是否支持运费险，0-不支持运费险，1-支持运费险。需要商户开通运费险服务，且当前类目支持运费险才会生效。 */
+  @JsonProperty("freight_insurance")
+  private Integer freightInsurance;
+
+  /** 是否支持假一赔三，0-不支持假一赔三，1-支持假一赔三。 */
+  @JsonProperty("fake_one_pay_three")
+  private Integer fakeOnePayThree;
+
+  /** 是否支持坏损包退，0-不支持坏损包退，1-支持坏损包退。 */
+  @JsonProperty("damage_guarantee")
+  private Integer damageGuarantee;
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductQuaInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductQuaInfo.java
new file mode 100644
index 0000000000..b411ebe80f
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductQuaInfo.java
@@ -0,0 +1,29 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.List;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 商品资质信息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ProductQuaInfo implements Serializable {
+
+  private static final long serialVersionUID = -71766140204505768L;
+
+  /** 商品资质id，对应获取类目信息中的字段product_qua_list[].qua_id */
+  @JsonProperty("qua_id")
+  private String quaId;
+
+  /** 商品资质图片列表 */
+  @JsonProperty("qua_url")
+  private List<String> quaUrl;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductSaleLimitInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductSaleLimitInfo.java
new file mode 100644
index 0000000000..9c067cc329
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/ProductSaleLimitInfo.java
@@ -0,0 +1,30 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 商品销售库存限制
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ProductSaleLimitInfo implements Serializable {
+
+  /** 是否受到管控，商品存在售卖限制时，固定返回1 */
+  @JsonProperty("is_limited")
+  private Integer limited;
+
+  /** 售卖限制标题 */
+  @JsonProperty("title")
+  private String title;
+
+  /** 售卖限制描述 */
+  @JsonProperty("sub_title")
+  private String subTitle;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuFastInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuFastInfo.java
new file mode 100644
index 0000000000..a461e6d952
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuFastInfo.java
@@ -0,0 +1,52 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 免审商品更新Sku数据
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class SkuFastInfo implements Serializable {
+
+  /** sku_id */
+  @JsonProperty("sku_id")
+  private String skuId;
+
+  /** 售卖价格，以分为单位，数字类型，最大不超过10000000（1000万元） */
+  @JsonProperty("sale_price")
+  private Integer salePrice;
+
+  @JsonProperty("stock_info")
+  private StockInfo stockInfo;
+
+  /** sku发货信息 */
+  @JsonProperty("sku_deliver_info")
+  private SkuDeliverInfo skuDeliverInfo;
+
+  /** 是否要删除当前sku */
+  @JsonProperty("is_delete")
+  private Boolean delete;
+
+
+  @Data
+  @NoArgsConstructor
+  public static class StockInfo implements Serializable {
+
+    /** 修改类型。1: 增加；2:减少；3:设置 */
+    @JsonProperty("diff_type")
+    protected Integer diffType;
+
+    /** 增加、减少或者设置的库存值 */
+    @JsonProperty("num")
+    protected Integer num;
+  }
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuInfo.java
index 3b46708039..22e75d7afc 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuInfo.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuInfo.java
@@ -54,7 +54,7 @@ public class SkuInfo implements Serializable {
 
   /** skuID */
   @JsonProperty("sku_id")
-  private Long skuId;
+  private String skuId;
 
   public SkuInfo() {
   }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuStockBatchList.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuStockBatchList.java
new file mode 100644
index 0000000000..71f995692f
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuStockBatchList.java
@@ -0,0 +1,23 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.List;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * spu库存列表
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class SkuStockBatchList implements Serializable {
+  private static final long serialVersionUID = -8082428962162052815L;
+
+  /** 库存信息 */
+  @JsonProperty("spu_stock_list")
+  private List<SpuStockInfo> spuStockList;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuStockBatchParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuStockBatchParam.java
new file mode 100644
index 0000000000..93b5cca798
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuStockBatchParam.java
@@ -0,0 +1,24 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.List;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class SkuStockBatchParam implements Serializable {
+
+  private static final long serialVersionUID = 3706326762056220559L;
+
+  /** 商品ID列表 注意这里是 productId ，序列化参数没有写错 */
+  @JsonProperty("product_id")
+  private List<String> productIds;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuStockBatchResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuStockBatchResponse.java
new file mode 100644
index 0000000000..eb188bdc79
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuStockBatchResponse.java
@@ -0,0 +1,24 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 批量查询sku库存响应
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class SkuStockBatchResponse extends WxChannelBaseResponse {
+
+    private static final long serialVersionUID = 7745444061881828137L;
+
+    /** 库存信息 */
+    @JsonProperty("data")
+    private SkuStockBatchList data;
+  }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuStockInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuStockInfo.java
index a0dccb1329..a480d3249b 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuStockInfo.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuStockInfo.java
@@ -29,7 +29,14 @@ public class SkuStockInfo implements Serializable {
   @JsonProperty("warehouse_stocks")
   private List<WarehouseStockInfo> warehouseStocks;
 
-  /** 库存总量：通用库存数量 + 限时抢购库存数量 + 区域库存总量 */
+  /**
+   * 普通查询：库存总量：通用库存数量 + 限时抢购库存数量 + 区域库存总量
+   * 批量查询：库存总量：通用库存数量 + 限时抢购库存数量 + 区域库存数量 + 达人专属计划营销库存数量
+   */
   @JsonProperty("total_stock_num")
   private Integer totalStockNum;
+
+  /** 达人专属计划营销库存数量 */
+  @JsonProperty("finder_stock_num")
+  private Integer finderTotalNum;
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuStockResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuStockResponse.java
index 9cbd6f18c0..683aece146 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuStockResponse.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SkuStockResponse.java
@@ -1,5 +1,6 @@
 package me.chanjar.weixin.channel.bean.product;
 
+import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
@@ -18,5 +19,6 @@ public class SkuStockResponse extends WxChannelBaseResponse {
   private static final long serialVersionUID = -2156342792354605826L;
 
   /** 库存信息 */
+  @JsonProperty("data")
   private SkuStockInfo data;
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuFastInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuFastInfo.java
new file mode 100644
index 0000000000..05e107779b
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuFastInfo.java
@@ -0,0 +1,28 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.List;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 商品免审更新参数
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class SpuFastInfo implements Serializable {
+
+  /** 商品ID */
+  @JsonProperty("product_id")
+  protected String productId;
+
+  /** SKU列表 */
+  @JsonProperty("skus")
+  protected List<SkuFastInfo> skus;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuGetResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuGetResponse.java
index b01682802f..ff15cbf0cb 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuGetResponse.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuGetResponse.java
@@ -25,4 +25,8 @@ public class SpuGetResponse extends WxChannelBaseResponse {
   /** 商品草稿数据，入参data_type==1时不返回该字段 */
   @JsonProperty("edit_product")
   private SpuInfo editProduct;
+
+  /** 当日售卖上限提醒，当店铺受到售卖管控时返回，没有返回本字段表示没有无额外限制 */
+  @JsonProperty("sale_limit_info")
+  private ProductSaleLimitInfo saleLimitInfo;
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuInfo.java
index 9db4c50f70..a160a31373 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuInfo.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuInfo.java
@@ -33,10 +33,18 @@ public class SpuInfo extends SpuSimpleInfo {
   @JsonProperty("head_imgs")
   private List<String> headImgs;
 
-  /** 发货方式，若为无需快递（仅对部分类目开放），则无需填写运费模版id。0:快递发货；1:无需快递；默认0 */
+  /** 发货方式：0-快递发货；1-无需快递，手机号发货；3-无需快递，可选发货账号类型，默认为0，若为无需快递，则无需填写运费模版id */
   @JsonProperty("deliver_method")
   private Integer deliverMethod;
 
+  /**
+   * 发货账号：1-微信openid；2-QQ号；3-手机号；4-邮箱。
+   * 可多选，只有deliver_method=3时，本参数有意义。
+   * 且当发货账号为微信、QQ和邮箱时，需要更新订单接口读取详情字段，详情参考订单接口的说明
+   */
+  @JsonProperty("deliver_acct_type")
+  private List<Integer> deliverAcctType;
+
   /** 商品详情 */
   @JsonProperty("desc_info")
   private DescriptionInfo descInfo;
@@ -45,6 +53,10 @@ public class SpuInfo extends SpuSimpleInfo {
   @JsonProperty("cats")
   private List<SpuCategory> cats;
 
+  /** 新类目树，商家需要先申请可使用类目 */
+  @JsonProperty("cats_v2")
+  private List<SpuCategory> catsV2;
+
   /** 商品参数 */
   @JsonProperty("attrs")
   private List<AttrInfo> attrs;
@@ -107,10 +119,24 @@ public class SpuInfo extends SpuSimpleInfo {
   @JsonProperty("product_type")
   private Integer productType;
 
-
   /**
    * 商品的售后信息
    */
   @JsonProperty("after_sale_info")
   private AfterSaleInfo afterSaleInfo;
+
+  /**
+   * 当商品类型位福袋抽奖商品（即product_type==2）且该抽奖商品由橱窗的自营商品导入生成时有值，
+   * 表示导入的来源商品id，其他场景下该字段无值或者值为0
+   */
+  @JsonProperty("src_product_id")
+  private String srcProductId;
+
+  /** 商品资质列表 */
+  @JsonProperty("product_qua_infos")
+  private List<ProductQuaInfo> productQuaInfos;
+
+  /** 尺码表信息 */
+  @JsonProperty("size_chart")
+  private SpuSizeChart sizeChart;
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuSimpleInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuSimpleInfo.java
index b1ab3febe7..3e84bb1492 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuSimpleInfo.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuSimpleInfo.java
@@ -15,7 +15,7 @@ public class SpuSimpleInfo implements Serializable {
 
   private static final long serialVersionUID = 5583726432139404883L;
 
-  /** 交易组件平台内部商品ID */
+  /** 商品ID */
   @JsonProperty("product_id")
   protected String productId;
 
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuSizeChart.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuSizeChart.java
new file mode 100644
index 0000000000..4e34ccfac8
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuSizeChart.java
@@ -0,0 +1,27 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.List;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 尺码表信息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class SpuSizeChart implements Serializable {
+
+  private static final long serialVersionUID = -5019617420608575610L;
+
+  /** 是否支持尺码表 */
+  @JsonProperty("enable")
+  private Boolean enable;
+
+  /** 尺码表 */
+  @JsonProperty("specification_list")
+  private List<SpuSizeChartItem> specificationList;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuSizeChartItem.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuSizeChartItem.java
new file mode 100644
index 0000000000..7ea4d0a66b
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuSizeChartItem.java
@@ -0,0 +1,55 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.List;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 尺码表
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class SpuSizeChartItem implements Serializable {
+
+  private static final long serialVersionUID = -3757716378584654974L;
+
+  /** 尺码属性名称 */
+  @JsonProperty("name")
+  private String name;
+
+  /** 尺码属性值的单位 */
+  @JsonProperty("unit")
+  private String unit;
+
+  /** 尺码属性值是否为区间 */
+  @JsonProperty("is_range")
+  private Boolean range;
+
+  /** 尺码值与尺码属性值的映射列表 */
+  @JsonProperty("value_list")
+  private List<ValueRange> valueList;
+
+  @Data
+  @NoArgsConstructor
+  public static class ValueRange implements Serializable {
+    /** 尺码值 */
+    @JsonProperty("key")
+    private String key;
+
+    /** 尺码属性值；尺码属性值为非区间时返回 */
+    @JsonProperty("value")
+    private String value;
+
+    /** 尺码属性值的左边界；尺码属性值为区间时返回 */
+    @JsonProperty("left")
+    private String left;
+
+    /** 尺码属性值的右边界；尺码属性值为区间时返回 */
+    @JsonProperty("right")
+    private String right;
+  }
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuStockInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuStockInfo.java
new file mode 100644
index 0000000000..4564f069b8
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuStockInfo.java
@@ -0,0 +1,25 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.List;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * SPU库存信息
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+public class SpuStockInfo implements Serializable {
+
+  /** 商品ID */
+  @JsonProperty("product_id")
+  protected String productId;
+
+  /** sku库存 */
+  @JsonProperty("sku_stock")
+  private List<SkuStockInfo> skuStock;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuUpdateInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuUpdateInfo.java
new file mode 100644
index 0000000000..f6214c5d78
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/SpuUpdateInfo.java
@@ -0,0 +1,24 @@
+package me.chanjar.weixin.channel.bean.product;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+/**
+ * 商品更新数据
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class SpuUpdateInfo extends SpuInfo {
+
+  /** 添加完成后是否立即上架。1:是；0:否；默认0 */
+  @JsonProperty("listing")
+  private Integer listing;
+
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/WarehouseStockInfo.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/WarehouseStockInfo.java
index bb239c9492..b0235534bb 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/WarehouseStockInfo.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/WarehouseStockInfo.java
@@ -6,6 +6,8 @@
 import lombok.NoArgsConstructor;
 
 /**
+ * 区域库存
+ *
  * @author <a href="https://github.com/lixize">Zeyes</a>
  */
 @Data
@@ -21,4 +23,8 @@ public class WarehouseStockInfo implements Serializable {
   /** 区域库存数量 */
   @JsonProperty("num")
   private Integer num;
+
+  /** 区域库存的锁定库存（已下单未支付的库存）数量 */
+  @JsonProperty("lock_stock")
+  private Integer lockStock;
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/link/ProductH5UrlResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/link/ProductH5UrlResponse.java
new file mode 100644
index 0000000000..0dee49f165
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/link/ProductH5UrlResponse.java
@@ -0,0 +1,22 @@
+package me.chanjar.weixin.channel.bean.product.link;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 商品H5短链 结果
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class ProductH5UrlResponse extends WxChannelBaseResponse {
+
+  /** 商品H5短链 */
+  @JsonProperty("product_h5url")
+  private String productH5url;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/link/ProductQrCodeResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/link/ProductQrCodeResponse.java
new file mode 100644
index 0000000000..a6876b78f1
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/link/ProductQrCodeResponse.java
@@ -0,0 +1,22 @@
+package me.chanjar.weixin.channel.bean.product.link;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 商品二维码 结果
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class ProductQrCodeResponse extends WxChannelBaseResponse {
+
+  /** 商品二维码 */
+  @JsonProperty("product_qrcode")
+  private String productQrcode;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/link/ProductTagLinkResponse.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/link/ProductTagLinkResponse.java
new file mode 100644
index 0000000000..59712130d8
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/product/link/ProductTagLinkResponse.java
@@ -0,0 +1,22 @@
+package me.chanjar.weixin.channel.bean.product.link;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+
+/**
+ * 商品口令 结果
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class ProductTagLinkResponse extends WxChannelBaseResponse {
+
+  /** 商品口令 */
+  @JsonProperty("product_taglink")
+  private String productTaglink;
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/token/StableToken.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/token/StableTokenParam.java
similarity index 93%
rename from weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/token/StableToken.java
rename to weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/token/StableTokenParam.java
index 72ce83d077..8bcacb649b 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/token/StableToken.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/token/StableTokenParam.java
@@ -17,7 +17,7 @@
 @NoArgsConstructor
 @AllArgsConstructor
 @JsonInclude(JsonInclude.Include.NON_NULL)
-public class StableToken implements Serializable {
+public class StableTokenParam implements Serializable {
   private static final long serialVersionUID = 6849364823232834171L;
 
   @JsonProperty("grant_type")
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/vip/VipParam.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/vip/VipOpenIdParam.java
similarity index 90%
rename from weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/vip/VipParam.java
rename to weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/vip/VipOpenIdParam.java
index e439641ed9..8f52ded878 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/vip/VipParam.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/bean/vip/VipOpenIdParam.java
@@ -17,7 +17,7 @@
 @NoArgsConstructor
 @JsonInclude(JsonInclude.Include.NON_NULL)
 @AllArgsConstructor
-public class VipParam implements Serializable {
+public class VipOpenIdParam implements Serializable {
   private static final long serialVersionUID = -7924178026258012317L;
   @JsonProperty("openid")
   private String openId;
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/common/ChannelWxError.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/common/ChannelWxError.java
index eb8cda4996..705eacc898 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/common/ChannelWxError.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/common/ChannelWxError.java
@@ -7,7 +7,9 @@
  * 微信视频号错误码
  *
  * @author <a href="https://github.com/lixize">Zeyes</a>
+ * @deprecated 请使用 {@link me.chanjar.weixin.common.error.WxError} 替代
  */
+@Deprecated
 public class ChannelWxError extends WxError {
 
   private static final long serialVersionUID = -2638512715814977441L;
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/config/WxChannelConfig.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/config/WxChannelConfig.java
index ad24234fb0..64344dae58 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/config/WxChannelConfig.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/config/WxChannelConfig.java
@@ -19,6 +19,14 @@ public interface WxChannelConfig {
    */
   String getAccessToken();
 
+  /**
+   * Is use stable access token api
+   *
+   * @link <a href="https://developers.weixin.qq.com/doc/store/API/basics/getStableAccessToken.html">获取稳定版AccessToken</a>
+   * @return the boolean
+   */
+  boolean isStableAccessToken();
+
   /**
    * Gets access token lock.
    *
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/config/impl/WxChannelDefaultConfigImpl.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/config/impl/WxChannelDefaultConfigImpl.java
index e32bcad83e..1c3930caf5 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/config/impl/WxChannelDefaultConfigImpl.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/config/impl/WxChannelDefaultConfigImpl.java
@@ -33,6 +33,8 @@ public class WxChannelDefaultConfigImpl implements WxChannelConfig {
   private volatile int httpProxyPort;
   private volatile String httpProxyUsername;
   private volatile String httpProxyPassword;
+  /** 是否使用稳定版获取accessToken接口 */
+  private volatile boolean stableAccessToken;
 
   private volatile int retrySleepMillis = 1000;
   private volatile int maxRetryTimes = 5;
@@ -63,6 +65,15 @@ public void setAccessToken(String accessToken) {
     this.accessToken = accessToken;
   }
 
+  @Override
+  public boolean isStableAccessToken() {
+    return stableAccessToken;
+  }
+
+  public void setStableAccessToken(boolean stableAccessToken) {
+    this.stableAccessToken = stableAccessToken;
+  }
+
   @Override
   public Lock getAccessTokenLock() {
     return this.accessTokenLock;
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/constant/MessageEventConstants.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/constant/MessageEventConstants.java
index 48cf268b06..675b5d8a57 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/constant/MessageEventConstants.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/constant/MessageEventConstants.java
@@ -16,12 +16,16 @@ public interface MessageEventConstants {
     String PRODUCT_SPU_UPDATE = "product_spu_update";
     /** 类目审核结果 */
     String PRODUCT_CATEGORY_AUDIT = "product_category_audit";
+    /** 库存不足 */
+    String PRODUCT_STOCK_NO_ENOUGH = "channels_ec_stock_no_enough";
     /** 订单下单 */
     String ORDER_NEW = "channels_ec_order_new";
     /** 订单取消 */
     String ORDER_CANCEL = "channels_ec_order_cancel";
     /** 订单支付成功 */
     String ORDER_PAY = "channels_ec_order_pay";
+    /** 订单待发货 */
+    String ORDER_WAIT_SHIPPING = "channels_ec_order_wait_shipping";
     /** 订单发货 */
     String ORDER_DELIVER = "channels_ec_order_deliver";
     /** 订单确认收货 */
@@ -55,6 +59,8 @@ public interface MessageEventConstants {
     String USER_COUPON_UNUSE = "channels_ec_user_coupon_unuse";
     /** 优惠券核销通知 */
     String USER_COUPON_USE = "channels_ec_user_coupon_use";
+    /** 发放团购优惠成功回调 */
+    String VOUCHER_SEND_SUCC = "channels_ec_voucher_send_succ";
     // 资金相关
     /** 结算账户变更回调 */
     String ACCOUNT_NOTIFY = "channels_ec_acct_notify";
@@ -83,4 +89,10 @@ public interface MessageEventConstants {
     // 分享员相关
     /** 分享员变更 **/
     String SHARER_CHANGE = "channels_ec_sharer_change";
+
+    // 店铺相关
+    /** 小店注销 */
+    String CLOSE_STORE = "channels_ec_close_store";
+    /** 小店修改 */
+    String SET_SHOP_NICKNAME = "set_shop_nickname";
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/constant/WxChannelApiUrlConstants.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/constant/WxChannelApiUrlConstants.java
index 1fddd1de84..b7d3add72a 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/constant/WxChannelApiUrlConstants.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/constant/WxChannelApiUrlConstants.java
@@ -55,6 +55,48 @@ public interface Category {
     String LIST_PASS_CATEGORY_URL = "https://api.weixin.qq.com/channels/ec/category/list/get";
   }
 
+  /** 主页管理相关接口 */
+  public interface HomePage {
+
+    /** 添加分类关联的商品 */
+    String ADD_TREE_PRODUCT_URL = "https://api.weixin.qq.com/channels/ec/store/classification/tree/product/add";
+    /** 删除分类关联的商品 */
+    String DEL_TREE_PRODUCT_URL = "https://api.weixin.qq.com/channels/ec/store/classification/tree/product/del";
+    /** 获取分类关联的商品ID列表 */
+    String LIST_TREE_PRODUCT_URL = "https://api.weixin.qq.com/channels/ec/store/classification/tree/product/get";
+    /** 设置展示在店铺主页的商品分类 */
+    String SET_SHOW_TREE_URL = "https://api.weixin.qq.com/channels/ec/store/classification/tree/set";
+    /** 获取在店铺主页展示的商品分类 */
+    String GET_SHOW_TREE_URL = "https://api.weixin.qq.com/channels/ec/store/classification/tree/get";
+
+    /** 获取主页展示商品列表 */
+    String LIST_WINDOW_PRODUCT_URL = "https://api.weixin.qq.com/channels/ec/store/window/product/list/get";
+    /** 重新排序主页展示商品 */
+    String REORDER_WINDOW_PRODUCT_URL = "https://api.weixin.qq.com/channels/ec/store/window/product/reorder";
+    /** 隐藏小店主页商品 */
+    String HIDE_WINDOW_PRODUCT_URL = "https://api.weixin.qq.com/channels/ec/store/window/product/hide";
+    /** 置顶小店主页商品 */
+    String TOP_WINDOW_PRODUCT_URL = "https://api.weixin.qq.com/channels/ec/store/window/product/settop";
+
+    /** 提交主页背景图申请 */
+    String APPLY_BACKGROUND_URL = "https://api.weixin.qq.com/channels/ec/basics/homepage/background/apply/submit";
+    /** 查询主页背景图 */
+    String GET_BACKGROUND_URL = "https://api.weixin.qq.com/channels/ec/basics/homepage/background/get";
+    /** 撤销主页背景图申请 */
+    String CANCEL_BACKGROUND_URL = "https://api.weixin.qq.com/channels/ec/basics/homepage/background/apply/cancel";
+    /** 清空主页背景图并撤销流程中的申请 */
+    String REMOVE_BACKGROUND_URL = "https://api.weixin.qq.com/channels/ec/basics/homepage/background/remove";
+
+    /** 提交精选展示位申请 */
+    String APPLY_BANNER_URL = "https://api.weixin.qq.com/channels/ec/basics/homepage/banner/apply/submit";
+    /** 查询精选展示位 */
+    String GET_BANNER_URL = "https://api.weixin.qq.com/channels/ec/basics/homepage/banner/get";
+    /** 撤销精选展示位申请 */
+    String CANCEL_BANNER_URL = "https://api.weixin.qq.com/channels/ec/basics/homepage/banner/apply/cancel";
+    /** 清空精选展示位并撤销流程中的申请 */
+    String REMOVE_BANNER_URL = "https://api.weixin.qq.com/channels/ec/basics/homepage/banner/remove";
+  }
+
   /** 品牌资质相关接口 */
   public interface Brand {
 
@@ -89,14 +131,24 @@ public interface Spu {
     String SPU_LIST_URL = "https://api.weixin.qq.com/channels/ec/product/list/get";
     /** 更新商品 */
     String SPU_UPDATE_URL = "https://api.weixin.qq.com/channels/ec/product/update";
+    /** 更新商品 */
+    String SPU_AUDIT_FREE_UPDATE_URL = "https://api.weixin.qq.com/channels/ec/product/auditfree";
     /** 上架商品 */
     String SPU_LISTING_URL = "https://api.weixin.qq.com/channels/ec/product/listing";
     /** 下架商品 */
     String SPU_DELISTING_URL = "https://api.weixin.qq.com/channels/ec/product/delisting";
     /** 撤回商品审核 */
     String CANCEL_AUDIT_URL = "https://api.weixin.qq.com/channels/ec/product/audit/cancel";
+    /** 获取商品H5短链 */
+    String SPU_H5URL_URL = "https://api.weixin.qq.com/channels/ec/product/h5url/get";
+    /** 获取商品二维码 */
+    String SPU_QRCODE_URL = "https://api.weixin.qq.com/channels/ec/product/qrcode/get";
+    /** 获取商品口令 */
+    String SPU_TAGLINK_URL = "https://api.weixin.qq.com/channels/ec/product/taglink/get";
     /** 获取实时库存 */
     String SPU_GET_STOCK_URL = "https://api.weixin.qq.com/channels/ec/product/stock/get";
+    /** 获取实时库存 */
+    String SPU_GET_STOCK_BATCH_URL = "https://api.weixin.qq.com/channels/ec/product/stock/batchget";
     /** 更新商品库存 */
     String SPU_UPDATE_STOCK_URL = "https://api.weixin.qq.com/channels/ec/product/stock/update";
     /** 添加限时抢购任务 */
@@ -155,6 +207,12 @@ public interface Order {
     String REJECT_ADDRESS_MODIFY_URL = "https://api.weixin.qq.com/channels/ec/order/addressmodify/reject";
     /** 订单搜索 */
     String ORDER_SEARCH_URL = "https://api.weixin.qq.com/channels/ec/order/search";
+    /** 上传生鲜质检信息 */
+    String UPLOAD_FRESH_INSPECT_URL = "https://api.weixin.qq.com/channels/ec/order/freshinspect/submit";
+    /** 兑换虚拟号 */
+    String VIRTUAL_TEL_NUMBER_URL = "https://api.weixin.qq.com/channels/ec/order/virtualtelnumber/get";
+    /** 解码订单包含的敏感数据 */
+    String DECODE_SENSITIVE_INFO_URL = "https://api.weixin.qq.com/channels/ec/order/sensitiveinfo/decode";
   }
 
   /** 售后相关接口 */
@@ -189,8 +247,9 @@ public interface Complaint {
 
   /** 物流相关接口 */
   public interface Delivery {
-
     /** 获取快递公司列表 */
+    String GET_DELIVERY_COMPANY_NEW_URL = "https://api.weixin.qq.com/channels/ec/order/deliverycompanylist/new/get";
+    /** 获取快递公司列表（旧） */
     String GET_DELIVERY_COMPANY_URL = "https://api.weixin.qq.com/channels/ec/order/deliverycompanylist/get";
     /** 订单发货 */
     String DELIVERY_SEND_URL = "https://api.weixin.qq.com/channels/ec/order/delivery/send";
@@ -258,6 +317,20 @@ public interface Share {
     String UNBIND_SHARER_URL = "https://api.weixin.qq.com/channels/ec/sharer/unbind";
   }
 
+  /** 合作账号相关接口 */
+  public interface Cooperation {
+    /** 获取合作账号列表 */
+    String LIST_COOPERATION_URL = "https://api.weixin.qq.com/channels/ec/cooperation/list";
+    /** 查看合作账号邀请状态 */
+    String GET_COOPERATION_STATUS_URL = "https://api.weixin.qq.com/channels/ec/cooperation/invitation/get";
+    /** 邀请合作账号 */
+    String GENERATE_QRCODE_COOPERATION_URL = "https://api.weixin.qq.com/channels/ec/cooperation/invitation/qrcode/generate";
+    /** 取消合作账号邀请 */
+    String CANCEL_COOPERATION_URL = "https://api.weixin.qq.com/channels/ec/cooperation/invitation/cancel";
+    /** 解绑合作账号 */
+    String UNBIND_COOPERATION_URL = "https://api.weixin.qq.com/channels/ec/cooperation/unbind";
+  }
+
   /** 资金相关接口 */
   public interface Fund {
 
@@ -266,9 +339,9 @@ public interface Fund {
     /** 获取结算账户 */
     String GET_BANK_ACCOUNT_URL = "https://api.weixin.qq.com/channels/ec/funds/getbankacct";
     /** 获取资金流水详情 */
-    String GET_BALANCE_FLOW_DETAIL_URL = "https://api.weixin.qq.com/channels/ec/league/funds/getfundsflowdetail";
+    String GET_BALANCE_FLOW_DETAIL_URL = "https://api.weixin.qq.com/channels/ec/funds/getfundsflowdetail";
     /** 获取资金流水列表 */
-    String GET_BALANCE_FLOW_LIST_URL = "https://api.weixin.qq.com/channels/ec/league/funds/getfundsflowlist";
+    String GET_BALANCE_FLOW_LIST_URL = "https://api.weixin.qq.com/channels/ec/funds/getfundsflowlist";
     /** 获取提现记录 */
     String GET_WITHDRAW_DETAIL_URL = "https://api.weixin.qq.com/channels/ec/funds/getwithdrawdetail";
     /** 获取提现记录列表 */
@@ -468,4 +541,31 @@ public interface CompassFinder {
      */
     String GET_SALE_PROFILE_DATA_URL = "https://api.weixin.qq.com/channels/ec/compass/finder/sale/profile/data/get";
   }
+
+  /**
+   * 罗盘商家版API
+   */
+  public interface CompassShop {
+
+    /** 获取电商数据概览 */
+    String GET_SHOP_OVERALL_URL = "https://api.weixin.qq.com/channels/ec/compass/shop/overall/get";
+    /** 获取授权视频号列表 */
+    String FINDER_AUTH_LIST_URL = "https://api.weixin.qq.com/channels/ec/compass/shop/finder/authorization/list/get";
+    /** 获取带货达人列表 */
+    String FINDER_LIST_URL = "https://api.weixin.qq.com/channels/ec/compass/shop/finder/list/get";
+    /** 获取带货数据概览 */
+    String GET_FINDER_OVERALL_URL = "https://api.weixin.qq.com/channels/ec/compass/shop/finder/overall/get";
+    /** 获取带货达人商品列表 */
+    String GET_FINDER_PRODUCT_LIST_URL = "https://api.weixin.qq.com/channels/ec/compass/shop/finder/product/list/get";
+    /** 获取带货达人商品数据 */
+    String GET_FINDER_PRODUCT_OVERALL_URL = "https://api.weixin.qq.com/channels/ec/compass/shop/finder/product/overall/get";
+    /** 获取店铺开播列表 */
+    String GET_LIVE_LIST_URL = "https://api.weixin.qq.com/channels/ec/compass/shop/live/list/get";
+    /** 获取商品详细信息 */
+    String GET_SHOP_PRODUCT_DATA_URL = "https://api.weixin.qq.com/channels/ec/compass/shop/product/data/get";
+    /** 获取商品列表 */
+    String GET_SHOP_PRODUCT_LIST_URL = "https://api.weixin.qq.com/channels/ec/compass/shop/product/list/get";
+    /** 获取店铺人群数据 */
+    String GET_SHOP_SALE_PROFILE_DATA_URL = "https://api.weixin.qq.com/channels/ec/compass/shop/sale/profile/data/get";
+  }
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/BannerType.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/BannerType.java
new file mode 100644
index 0000000000..7cf11eb9ce
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/BannerType.java
@@ -0,0 +1,37 @@
+package me.chanjar.weixin.channel.enums;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+/**
+ * 展示位类型
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@JsonFormat(shape = JsonFormat.Shape.OBJECT)
+public enum BannerType {
+
+  /** 1	商品 */
+  PRODUCT(1, "商品"),
+  /** 3	视频号 */
+  CHANNEL(3, "视频号"),
+  /** 4	公众号 */
+  MP(4, "公众号");
+
+  ;
+
+  private final int key;
+  private final String value;
+
+  BannerType(int key, String value) {
+    this.key = key;
+    this.value = value;
+  }
+
+  public int getKey() {
+    return key;
+  }
+
+  public String getValue() {
+    return value;
+  }
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/FundsType.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/FundsType.java
index ea3f8873ec..125e8c39c7 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/FundsType.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/FundsType.java
@@ -24,12 +24,23 @@ public enum FundsType {
     /** 8 运费险分账 */
     FREIGHT_SHARE(8, "运费险分账"),
     /** 9 联盟平台抽佣 */
-    LEAGUE_COMMISSION(9, "联盟平台抽佣"),
-    /** 10 小店抽佣 */
-    SHOP_COMMISSION(10, "小店抽佣"),
+    LEAGUE_PLAT_COMMISSION(9, "联盟平台抽佣"),
+    /** 10 联盟抽佣 */
+    LEAGUE_COMMISSION(10, "联盟抽佣"),
+    /** 11台抽佣 */
+    PLATFORM_COMMISSION(11, "平台抽佣"),
+    /** 12 团长抽佣 */
+    LEADER_COMMISSION(12, "团长抽佣"),
+    /** 13 返佣人气卡 */
+    POPULARITY_CARD(13, "返佣人气卡"),
+    /** 14 极速退款垫资金 */
+    FAST_REFUND(14, "极速退款垫资金"),
+    /** 15 极速退款垫资回补 */
+    FAST_REFUND_REPLENISHMENT(15, "极速退款垫资回补"),
+    /** 16 运费险 */
+    FREIGHT_INSURANCE(16, "运费险"),
     /** 99 分账 */
     SHARE(99, "分账"),
-
     ;
 
     private final int key;
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/PackageAuditItemType.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/PackageAuditItemType.java
new file mode 100644
index 0000000000..2929b2d381
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/PackageAuditItemType.java
@@ -0,0 +1,37 @@
+package me.chanjar.weixin.channel.enums;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+/**
+ * 商品打包审核项
+ *
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@JsonFormat(shape = JsonFormat.Shape.OBJECT)
+public enum PackageAuditItemType {
+  /** 商品快递单图片url */
+  EXPRESS_PIC("product_express_pic_url", "商品快递单图片url"),
+  /** 商品包装箱图片url */
+  BOX_PIC("product_packaging_box_pic_url", "商品包装箱图片url"),
+  /** 商品开箱图片url */
+  UNBOXING_PIC("product_unboxing_pic_url", "商品开箱图片url"),
+  /** 商品单个细节图片url */
+  DETAIL_PIC("single_product_detail_pic_url", "商品单个细节图片url"),
+  ;
+
+  public final String key;
+  public final String value;
+
+  PackageAuditItemType(String key, String value) {
+    this.key = key;
+    this.value = value;
+  }
+
+  public String getKey() {
+    return key;
+  }
+
+  public String getValue() {
+    return value;
+  }
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/PromoteType.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/PromoteType.java
index fa0bd60913..c1ba1a3561 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/PromoteType.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/PromoteType.java
@@ -9,7 +9,14 @@
  */
 @JsonFormat(shape = JsonFormat.Shape.OBJECT)
 public enum PromoteType {
-  PROMOTE_TYPE_SHOP(1, "小店内推广");
+  /** 1	小店内推广 */
+  PROMOTE_TYPE_SHOP(1, "小店内推广"),
+  /** 9	会员券 */
+  MEMBER(9, "会员券"),
+  /** 10	会员开卡礼券 */
+  MEMBER_CARD(10, "会员开卡礼券"),
+
+  ;
 
   private final int key;
   private final String val;
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/SendTime.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/SendTime.java
index 85e4d4f0d6..9b5bc6e809 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/SendTime.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/SendTime.java
@@ -23,7 +23,11 @@ public enum SendTime {
   TWENTYFOUR_HOUR("SendTime_TWENTYFOUR_HOUR", "24小时内发货"),
   /** 48小时内发货 */
   FOUTYEIGHT_HOUR("SendTime_FOUTYEIGHT_HOUR", "48小时内发货"),
-  /** 3天内发货 */
+  /**
+   * 3天内发货
+   * @deprecated 已不支持，微信小店发货管理规则调整
+   */
+  @Deprecated
   THREE_DAY("SendTime_THREE_DAY", "3天内发货"),
 //    /** 5天内发货 */
 //    FIVE_DAY("SendTime_FIVE_DAY", "5天内发货"),
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/ShareScene.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/ShareScene.java
index b4428dbb24..e2fb09d132 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/ShareScene.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/ShareScene.java
@@ -19,7 +19,18 @@ public enum ShareScene {
   CHANNEL_HOME(4, "视频号主页"),
   /** 5 商品详情页 */
   PRODUCT_DETAIL(5, "商品详情页"),
-
+  /** 6	带商品的公众号文章 */
+  MP_ARTICLE(6, "带商品的公众号文章"),
+  /** 7	商品链接 */
+  PRODUCT_LINK(7, "商品链接"),
+  /** 8	商品二维码 */
+  PRODUCT_QR_CODE(8, "商品二维码"),
+  /** 9	商品口令 */
+  PRODUCT_TAG_LINK(9, "商品口令"),
+  /** 12 视频号橱窗链接 */
+  WINDOW_LINK(12, "视频号橱窗链接"),
+  /** 13 视频号橱窗二维码 */
+  WINDOW_QR_CODE(13, "视频号橱窗二维码"),
   ;
 
 
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/SpuEditStatus.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/SpuEditStatus.java
index 3d6063b8cf..71c71d5a26 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/SpuEditStatus.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/SpuEditStatus.java
@@ -20,7 +20,13 @@ public enum SpuEditStatus {
   /** 4 审核成功 */
   SUCCESS(4, "审核成功"),
   /** 5 商品信息写入中 */
-  WRITING(5, "商品信息写入中");
+  WRITING(5, "商品信息写入中"),
+  /** 7	商品异步提交，上传中（处于该状态的商品调用上架商品接口会返回10020067） */
+  ASYNC_WRITING(7, "商品异步提交，上传中"),
+  /** 8	商品异步提交，上传失败（请重新提交） */
+  ASYNC_FAIL(8, "商品异步提交，上传失败"),
+
+  ;
 
   private final int status;
   private final String desc;
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/SpuStatus.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/SpuStatus.java
index a74fee6b07..8f88d5ffac 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/SpuStatus.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/SpuStatus.java
@@ -16,10 +16,20 @@ public enum SpuStatus {
   UP(5, "上架"),
   /** 6 回收站 */
   TRASH(6, "回收站"),
+  /** 9 彻底删除，商品无法再进行任何操作 */
+  DELETE(9, "彻底删除"),
   /** 11 自主下架 */
   DOWN(11, "自主下架"),
   /** 13 违规下架/风控系统下架 */
-  SYSTEM_DOWN(13, "违规下架");
+  SYSTEM_DOWN(13, "违规下架/风控系统下架"),
+  /** 14 保证金不足下架 */
+  DEPOSIT_INSUFFICIENT(14, "保证金不足下架"),
+  /** 15 品牌过期下架 */
+  BRAND_EXPIRED(15, "品牌过期下架"),
+  /** 20 商品被封禁 */
+  BAN(20, "商品被封禁"),
+
+;
 
   private final int status;
   private final String desc;
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/WxChannelErrorMsgEnum.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/WxChannelErrorMsgEnum.java
index 4a699c20d0..18e88c0b08 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/WxChannelErrorMsgEnum.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/enums/WxChannelErrorMsgEnum.java
@@ -8,7 +8,9 @@
  * 微信视频号全局返回码
  *
  * @author <a href="https://github.com/lixize">Zeyes</a>
+ * @deprecated 请使用 {@link me.chanjar.weixin.common.error.WxChannelErrorMsgEnum} 替代
  */
+@Deprecated
 @Getter
 public enum WxChannelErrorMsgEnum {
   /**
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/executor/ApacheHttpChannelFileUploadRequestExecutor.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/executor/ApacheHttpChannelFileUploadRequestExecutor.java
new file mode 100644
index 0000000000..5ccb6f5cb1
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/executor/ApacheHttpChannelFileUploadRequestExecutor.java
@@ -0,0 +1,47 @@
+package me.chanjar.weixin.channel.executor;
+
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.ResponseHandler;
+import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpHost;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.mime.HttpMultipartMode;
+import org.apache.http.entity.mime.MultipartEntityBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
+
+import java.io.File;
+import java.io.IOException;
+
+public class ApacheHttpChannelFileUploadRequestExecutor extends ChannelFileUploadRequestExecutor<CloseableHttpClient, HttpHost> {
+  public ApacheHttpChannelFileUploadRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
+
+  @Override
+  public String execute(String uri, File file, WxType wxType) throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+    if (file != null) {
+      HttpEntity entity = MultipartEntityBuilder
+        .create()
+        .addBinaryBody("media", file)
+        .setMode(HttpMultipartMode.RFC6532)
+        .build();
+      httpPost.setEntity(entity);
+    }
+    return requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+  }
+
+  @Override
+  public void execute(String uri, File data, ResponseHandler<String> handler, WxType wxType)
+    throws WxErrorException, IOException {
+    handler.handle(this.execute(uri, data, wxType));
+  }
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/executor/ApacheHttpChannelMediaDownloadRequestExecutor.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/executor/ApacheHttpChannelMediaDownloadRequestExecutor.java
new file mode 100644
index 0000000000..b9b44b60e2
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/executor/ApacheHttpChannelMediaDownloadRequestExecutor.java
@@ -0,0 +1,90 @@
+package me.chanjar.weixin.channel.executor;
+
+import me.chanjar.weixin.channel.bean.image.ChannelImageResponse;
+import me.chanjar.weixin.channel.util.JsonUtils;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.ResponseHandler;
+import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler;
+import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.Header;
+import org.apache.http.HttpHost;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.entity.ContentType;
+import org.apache.http.impl.client.CloseableHttpClient;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ApacheHttpChannelMediaDownloadRequestExecutor extends ChannelMediaDownloadRequestExecutor<CloseableHttpClient, HttpHost> {
+
+  public ApacheHttpChannelMediaDownloadRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp, File tmpDirFile) {
+    super(requestHttp, tmpDirFile);
+  }
+
+  @Override
+  public ChannelImageResponse execute(String uri, String data, WxType wxType) throws WxErrorException, IOException {
+    if (data != null) {
+      if (uri.indexOf('?') == -1) {
+        uri += '?';
+      }
+      uri += uri.endsWith("?") ? data : '&' + data;
+    }
+
+    HttpGet httpGet = new HttpGet(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpGet.setConfig(config);
+    }
+
+    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpGet);
+         InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) {
+      Header[] contentTypeHeader = response.getHeaders("Content-Type");
+      String contentType = null;
+      if (contentTypeHeader != null && contentTypeHeader.length > 0) {
+        contentType = contentTypeHeader[0].getValue();
+        if (contentType.startsWith(ContentType.APPLICATION_JSON.getMimeType())) {
+          // application/json; encoding=utf-8 下载媒体文件出错
+          String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
+          return JsonUtils.decode(responseContent, ChannelImageResponse.class);
+        }
+      }
+
+      String fileName = this.getFileName(response);
+      if (StringUtils.isBlank(fileName)) {
+        fileName = String.valueOf(System.currentTimeMillis());
+      }
+
+      String baseName = FilenameUtils.getBaseName(fileName);
+      if (StringUtils.isBlank(fileName) || baseName.length() < 3) {
+        baseName = String.valueOf(System.currentTimeMillis());
+      }
+      String extension = FilenameUtils.getExtension(fileName);
+      if (StringUtils.isBlank(extension)) {
+        extension = "unknown";
+      }
+      File file = createTmpFile(inputStream, baseName, extension, tmpDirFile);
+      return new ChannelImageResponse(file, contentType);
+    }
+  }
+
+  private String getFileName(CloseableHttpResponse response) throws WxErrorException {
+    Header[] contentDispositionHeader = response.getHeaders("Content-disposition");
+    if (contentDispositionHeader == null || contentDispositionHeader.length == 0) {
+      return createDefaultFileName();
+    }
+    return this.extractFileNameFromContentString(contentDispositionHeader[0].getValue());
+  }
+
+  @Override
+  public void execute(String uri, String data, ResponseHandler<ChannelImageResponse> handler, WxType wxType)
+    throws WxErrorException, IOException {
+    handler.handle(this.execute(uri, data, wxType));
+  }
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/executor/ChannelFileUploadRequestExecutor.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/executor/ChannelFileUploadRequestExecutor.java
index 576f1c286a..78a6735192 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/executor/ChannelFileUploadRequestExecutor.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/executor/ChannelFileUploadRequestExecutor.java
@@ -1,66 +1,35 @@
 package me.chanjar.weixin.channel.executor;
 
-
-import java.io.File;
-import java.io.IOException;
-import me.chanjar.weixin.common.enums.WxType;
-import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
-import me.chanjar.weixin.common.util.http.ResponseHandler;
-import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpHost;
-import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.entity.mime.HttpMultipartMode;
-import org.apache.http.entity.mime.MultipartEntityBuilder;
-import org.apache.http.impl.client.CloseableHttpClient;
+
+import java.io.File;
 
 /**
  * 视频号小店 图片上传接口 请求的参数是File, 返回的结果是String
  *
  * @author <a href="https://github.com/lixize">Zeyes</a>
  */
-public class ChannelFileUploadRequestExecutor implements RequestExecutor<String, File> {
+public abstract class ChannelFileUploadRequestExecutor<H, P> implements RequestExecutor<String, File> {
 
-  protected RequestHttp<CloseableHttpClient, HttpHost> requestHttp;
+  protected RequestHttp<H, P> requestHttp;
 
-  public ChannelFileUploadRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+  public ChannelFileUploadRequestExecutor(RequestHttp<H, P> requestHttp) {
     this.requestHttp = requestHttp;
   }
 
-  @Override
-  public String execute(String uri, File file, WxType wxType) throws WxErrorException, IOException {
-    HttpPost httpPost = new HttpPost(uri);
-    if (requestHttp.getRequestHttpProxy() != null) {
-      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
-      httpPost.setConfig(config);
-    }
-    if (file != null) {
-      HttpEntity entity = MultipartEntityBuilder
-        .create()
-        .addBinaryBody("media", file)
-        .setMode(HttpMultipartMode.RFC6532)
-        .build();
-      httpPost.setEntity(entity);
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<String, File> create(RequestHttp<?, ?> requestHttp) {
+    switch (requestHttp.getRequestType()) {
+      case APACHE_HTTP:
+        return new ApacheHttpChannelFileUploadRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp);
+      case HTTP_COMPONENTS:
+        return new HttpComponentsChannelFileUploadRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp);
+      default:
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
-    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
-      return Utf8ResponseHandler.INSTANCE.handleResponse(response);
-    } finally {
-      httpPost.releaseConnection();
-    }
-  }
-
-  @Override
-  public void execute(String uri, File data, ResponseHandler<String> handler, WxType wxType)
-    throws WxErrorException, IOException {
-    handler.handle(this.execute(uri, data, wxType));
-  }
-
-  public static RequestExecutor<String, File> create(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
-    return new ChannelFileUploadRequestExecutor(requestHttp);
   }
 
 }
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/executor/ChannelMediaDownloadRequestExecutor.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/executor/ChannelMediaDownloadRequestExecutor.java
index 1b81dc6d15..dd4bf0ba89 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/executor/ChannelMediaDownloadRequestExecutor.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/executor/ChannelMediaDownloadRequestExecutor.java
@@ -1,6 +1,9 @@
 package me.chanjar.weixin.channel.executor;
 
-import static org.apache.commons.io.FileUtils.openOutputStream;
+import me.chanjar.weixin.channel.bean.image.ChannelImageResponse;
+import me.chanjar.weixin.common.util.http.RequestExecutor;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import org.apache.commons.io.IOUtils;
 
 import java.io.File;
 import java.io.IOException;
@@ -9,102 +12,38 @@
 import java.util.UUID;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import lombok.extern.slf4j.Slf4j;
-import me.chanjar.weixin.channel.bean.image.ChannelImageResponse;
-import me.chanjar.weixin.channel.util.JsonUtils;
-import me.chanjar.weixin.common.enums.WxType;
-import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.common.util.http.RequestExecutor;
-import me.chanjar.weixin.common.util.http.RequestHttp;
-import me.chanjar.weixin.common.util.http.ResponseHandler;
-import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler;
-import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler;
-import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.http.Header;
-import org.apache.http.HttpHost;
-import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.entity.ContentType;
-import org.apache.http.impl.client.CloseableHttpClient;
+
+import static org.apache.commons.io.FileUtils.openOutputStream;
 
 /**
  * 下载媒体文件请求执行器
  *
  * @author <a href="https://github.com/lixize">Zeyes</a>
  */
-@Slf4j
-public class ChannelMediaDownloadRequestExecutor implements RequestExecutor<ChannelImageResponse, String> {
+public abstract class ChannelMediaDownloadRequestExecutor<H, P> implements RequestExecutor<ChannelImageResponse, String> {
 
-  protected RequestHttp<CloseableHttpClient, HttpHost> requestHttp;
+  protected RequestHttp<H, P> requestHttp;
   protected File tmpDirFile;
 
   private static final Pattern PATTERN = Pattern.compile(".*filename=\"(.*)\"");
 
-  public ChannelMediaDownloadRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp, File tmpDirFile) {
+  public ChannelMediaDownloadRequestExecutor(RequestHttp<H, P> requestHttp, File tmpDirFile) {
     this.requestHttp = requestHttp;
     this.tmpDirFile = tmpDirFile;
   }
 
-  @Override
-  public ChannelImageResponse execute(String uri, String data, WxType wxType) throws WxErrorException, IOException {
-    if (data != null) {
-      if (uri.indexOf('?') == -1) {
-        uri += '?';
-      }
-      uri += uri.endsWith("?") ? data : '&' + data;
-    }
-
-    HttpGet httpGet = new HttpGet(uri);
-    if (requestHttp.getRequestHttpProxy() != null) {
-      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
-      httpGet.setConfig(config);
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<ChannelImageResponse, String> create(RequestHttp<?, ?> requestHttp, File tmpDirFile) {
+    switch (requestHttp.getRequestType()) {
+      case APACHE_HTTP:
+        return new ApacheHttpChannelMediaDownloadRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp, tmpDirFile);
+      case HTTP_COMPONENTS:
+        return new HttpComponentsChannelMediaDownloadRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp, tmpDirFile);
+      default:
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
-
-    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpGet);
-      InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) {
-      Header[] contentTypeHeader = response.getHeaders("Content-Type");
-      String contentType = null;
-      if (contentTypeHeader != null && contentTypeHeader.length > 0) {
-        contentType = contentTypeHeader[0].getValue();
-        if (contentType.startsWith(ContentType.APPLICATION_JSON.getMimeType())) {
-          // application/json; encoding=utf-8 下载媒体文件出错
-          String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
-          return JsonUtils.decode(responseContent, ChannelImageResponse.class);
-        }
-      }
-
-      String fileName = this.getFileName(response);
-      if (StringUtils.isBlank(fileName)) {
-        fileName = String.valueOf(System.currentTimeMillis());
-      }
-
-      String baseName = FilenameUtils.getBaseName(fileName);
-      if (StringUtils.isBlank(fileName) || baseName.length() < 3) {
-        baseName = String.valueOf(System.currentTimeMillis());
-      }
-      String extension = FilenameUtils.getExtension(fileName);
-      if (StringUtils.isBlank(extension)) {
-        extension = "unknown";
-      }
-      File file = createTmpFile(inputStream, baseName, extension, tmpDirFile);
-      ChannelImageResponse result = new ChannelImageResponse(file, contentType);
-      return result;
-    } finally {
-      httpGet.releaseConnection();
-    }
-  }
-
-  @Override
-  public void execute(String uri, String data, ResponseHandler<ChannelImageResponse> handler, WxType wxType)
-    throws WxErrorException, IOException {
-    handler.handle(this.execute(uri, data, wxType));
-  }
-
-  public static RequestExecutor<ChannelImageResponse, String> create(RequestHttp requestHttp, File tmpDirFile) {
-    return new ChannelMediaDownloadRequestExecutor(requestHttp, tmpDirFile);
   }
 
   /**
@@ -125,20 +64,12 @@ public static File createTmpFile(InputStream inputStream, String name, String ex
     return resultFile;
   }
 
-  private String getFileName(CloseableHttpResponse response) throws WxErrorException {
-    Header[] contentDispositionHeader = response.getHeaders("Content-disposition");
-    if (contentDispositionHeader == null || contentDispositionHeader.length == 0) {
-      return createDefaultFileName();
-    }
-    return this.extractFileNameFromContentString(contentDispositionHeader[0].getValue());
-  }
-
-  private String createDefaultFileName() {
+  protected String createDefaultFileName() {
     return UUID.randomUUID().toString();
   }
 
-  private String extractFileNameFromContentString(String content) throws WxErrorException {
-    if (content == null || content.length() == 0) {
+  protected String extractFileNameFromContentString(String content) {
+    if (content == null || content.isEmpty()) {
       return createDefaultFileName();
     }
     Matcher m = PATTERN.matcher(content);
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/executor/HttpComponentsChannelFileUploadRequestExecutor.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/executor/HttpComponentsChannelFileUploadRequestExecutor.java
new file mode 100644
index 0000000000..3b1e7076a9
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/executor/HttpComponentsChannelFileUploadRequestExecutor.java
@@ -0,0 +1,47 @@
+package me.chanjar.weixin.channel.executor;
+
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.ResponseHandler;
+import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
+import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.File;
+import java.io.IOException;
+
+public class HttpComponentsChannelFileUploadRequestExecutor extends ChannelFileUploadRequestExecutor<CloseableHttpClient, HttpHost> {
+  public HttpComponentsChannelFileUploadRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
+
+  @Override
+  public String execute(String uri, File file, WxType wxType) throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+    if (file != null) {
+      HttpEntity entity = MultipartEntityBuilder
+        .create()
+        .addBinaryBody("media", file)
+        .setMode(HttpMultipartMode.EXTENDED)
+        .build();
+      httpPost.setEntity(entity);
+    }
+    return requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+  }
+
+  @Override
+  public void execute(String uri, File data, ResponseHandler<String> handler, WxType wxType)
+    throws WxErrorException, IOException {
+    handler.handle(this.execute(uri, data, wxType));
+  }
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/executor/HttpComponentsChannelMediaDownloadRequestExecutor.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/executor/HttpComponentsChannelMediaDownloadRequestExecutor.java
new file mode 100644
index 0000000000..95a13f6c86
--- /dev/null
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/executor/HttpComponentsChannelMediaDownloadRequestExecutor.java
@@ -0,0 +1,94 @@
+package me.chanjar.weixin.channel.executor;
+
+import me.chanjar.weixin.channel.bean.image.ChannelImageResponse;
+import me.chanjar.weixin.channel.util.JsonUtils;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.ResponseHandler;
+import me.chanjar.weixin.common.util.http.hc.InputStreamResponseHandler;
+import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hc.client5.http.ClientProtocolException;
+import org.apache.hc.client5.http.classic.methods.HttpGet;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class HttpComponentsChannelMediaDownloadRequestExecutor extends ChannelMediaDownloadRequestExecutor<CloseableHttpClient, HttpHost> {
+
+  public HttpComponentsChannelMediaDownloadRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp, File tmpDirFile) {
+    super(requestHttp, tmpDirFile);
+  }
+
+  @Override
+  public ChannelImageResponse execute(String uri, String data, WxType wxType) throws WxErrorException, IOException {
+    if (data != null) {
+      if (uri.indexOf('?') == -1) {
+        uri += '?';
+      }
+      uri += uri.endsWith("?") ? data : '&' + data;
+    }
+
+    HttpGet httpGet = new HttpGet(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpGet.setConfig(config);
+    }
+
+    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpGet);
+         InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) {
+      Header[] contentTypeHeader = response.getHeaders("Content-Type");
+      String contentType = null;
+      if (contentTypeHeader != null && contentTypeHeader.length > 0) {
+        contentType = contentTypeHeader[0].getValue();
+        if (contentType.startsWith(ContentType.APPLICATION_JSON.getMimeType())) {
+          // application/json; encoding=utf-8 下载媒体文件出错
+          String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
+          return JsonUtils.decode(responseContent, ChannelImageResponse.class);
+        }
+      }
+
+      String fileName = this.getFileName(response);
+      if (StringUtils.isBlank(fileName)) {
+        fileName = String.valueOf(System.currentTimeMillis());
+      }
+
+      String baseName = FilenameUtils.getBaseName(fileName);
+      if (StringUtils.isBlank(fileName) || baseName.length() < 3) {
+        baseName = String.valueOf(System.currentTimeMillis());
+      }
+      String extension = FilenameUtils.getExtension(fileName);
+      if (StringUtils.isBlank(extension)) {
+        extension = "unknown";
+      }
+      File file = createTmpFile(inputStream, baseName, extension, tmpDirFile);
+      return new ChannelImageResponse(file, contentType);
+    } catch (HttpException httpException) {
+      throw new ClientProtocolException(httpException.getMessage(), httpException);
+    }
+  }
+
+  private String getFileName(CloseableHttpResponse response) throws WxErrorException {
+    Header[] contentDispositionHeader = response.getHeaders("Content-disposition");
+    if (contentDispositionHeader == null || contentDispositionHeader.length == 0) {
+      return createDefaultFileName();
+    }
+    return this.extractFileNameFromContentString(contentDispositionHeader[0].getValue());
+  }
+
+  @Override
+  public void execute(String uri, String data, ResponseHandler<ChannelImageResponse> handler, WxType wxType)
+    throws WxErrorException, IOException {
+    handler.handle(this.execute(uri, data, wxType));
+  }
+}
diff --git a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/message/WxChannelMessageRouter.java b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/message/WxChannelMessageRouter.java
index 8ccc2c5050..3236e18303 100644
--- a/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/message/WxChannelMessageRouter.java
+++ b/weixin-java-channel/src/main/java/me/chanjar/weixin/channel/message/WxChannelMessageRouter.java
@@ -121,6 +121,7 @@ public Object route(final WxChannelMessage message, final String content, final
     final Map<String, Object> context, final WxChannelService service, final WxSessionManager sessionManager) {
     // 如果是重复消息，那么就不做处理
     if (isMsgDuplicated(message)) {
+      log.info("收到重复消息，{}", content);
       return null;
     }
 
@@ -136,7 +137,7 @@ public Object route(final WxChannelMessage message, final String content, final
       }
     }
 
-    if (matchRules.size() == 0) {
+    if (matchRules.isEmpty()) {
       return null;
     }
     final List<Future<?>> futures = new ArrayList<>();
@@ -156,7 +157,7 @@ public Object route(final WxChannelMessage message, final String content, final
       }
     }
 
-    if (futures.size() > 0) {
+    if (!futures.isEmpty()) {
       this.executorService.submit(() -> {
         for (Future<?> future : futures) {
           try {
@@ -178,7 +179,7 @@ public Object route(final WxChannelMessage message, final String content, final
    * @param wxMessage 消息
    * @return 是否重复
    */
-  private boolean isMsgDuplicated(WxChannelMessage wxMessage) {
+  protected boolean isMsgDuplicated(WxChannelMessage wxMessage) {
     String messageId = this.generateMessageId(wxMessage);
     return this.messageDuplicateChecker.isDuplicate(messageId);
   }
@@ -188,7 +189,7 @@ private boolean isMsgDuplicated(WxChannelMessage wxMessage) {
    *
    * @return 消息id
    */
-  private String generateMessageId(WxChannelMessage wxMessage) {
+  protected String generateMessageId(WxChannelMessage wxMessage) {
     StringBuilder sb = new StringBuilder();
     if (wxMessage.getMsgId() == null) {
       sb.append(wxMessage.getCreateTime())
@@ -211,10 +212,10 @@ private String generateMessageId(WxChannelMessage wxMessage) {
    *
    * @param sessionManager session管理器
    * @param message 消息
-   * @param sync 是否同步 打印log用
+   * @param async 是否异步 打印log用
    */
-  private void sessionEndAccess(WxSessionManager sessionManager, WxChannelMessage message, boolean sync) {
-    log.debug("End session access: async={}, sessionId={}", sync, message.getFromUser());
+  private void sessionEndAccess(WxSessionManager sessionManager, WxChannelMessage message, boolean async) {
+    log.debug("End session access: async={}, sessionId={}", async, message.getFromUser());
     InternalSession session = ((InternalSessionManager) sessionManager).findSession(message.getFromUser());
     if (session != null) {
       session.endAccess();
diff --git a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelBasicServiceImplTest.java b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelBasicServiceImplTest.java
index 5673d85439..120e11245a 100644
--- a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelBasicServiceImplTest.java
+++ b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelBasicServiceImplTest.java
@@ -20,6 +20,8 @@
 import me.chanjar.weixin.channel.util.JsonUtils;
 import me.chanjar.weixin.common.error.WxErrorException;
 import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
@@ -29,9 +31,19 @@
 @Guice(modules = ApiTestModule.class)
 public class WxChannelBasicServiceImplTest {
 
+  private static final Logger log = LoggerFactory.getLogger(WxChannelBasicServiceImplTest.class);
+
   @Inject
   private WxChannelService channelService;
 
+  @Test
+  public void testGetAccessToken() throws WxErrorException {
+    String accessToken = channelService.getAccessToken();
+    assertNotNull(accessToken);
+    log.info("accessToken: \n{}\n\n", accessToken);
+    System.out.println(accessToken);
+  }
+
   @Test
   public void testGetShopInfo() throws WxErrorException {
     WxChannelBasicService basicService = channelService.getBasicService();
diff --git a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelCategoryServiceImplTest.java b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelCategoryServiceImplTest.java
index 9b1a62ada3..125e061cd8 100644
--- a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelCategoryServiceImplTest.java
+++ b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelCategoryServiceImplTest.java
@@ -4,18 +4,24 @@
 import static org.testng.Assert.assertTrue;
 
 import com.google.inject.Inject;
-import java.util.ArrayList;
 import java.util.List;
+import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.channel.api.WxChannelCategoryService;
 import me.chanjar.weixin.channel.api.WxChannelService;
 import me.chanjar.weixin.channel.bean.audit.AuditApplyResponse;
 import me.chanjar.weixin.channel.bean.audit.AuditResponse;
+import me.chanjar.weixin.channel.bean.audit.CategoryAuditInfo;
+import me.chanjar.weixin.channel.bean.audit.CategoryAuditRequest;
 import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+import me.chanjar.weixin.channel.bean.category.CategoryAndQualificationList;
 import me.chanjar.weixin.channel.bean.category.CategoryDetailResult;
+import me.chanjar.weixin.channel.bean.category.CategoryQualification;
 import me.chanjar.weixin.channel.bean.category.CategoryQualificationResponse;
 import me.chanjar.weixin.channel.bean.category.PassCategoryResponse;
 import me.chanjar.weixin.channel.bean.category.ShopCategory;
+import me.chanjar.weixin.channel.bean.category.ShopCategoryResponse;
 import me.chanjar.weixin.channel.test.ApiTestModule;
+import me.chanjar.weixin.channel.util.JsonUtils;
 import me.chanjar.weixin.common.error.WxErrorException;
 import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
@@ -24,6 +30,7 @@
 /**
  * @author <a href="https://github.com/lixize">Zeyes</a>
  */
+@Slf4j
 @Guice(modules = ApiTestModule.class)
 public class WxChannelCategoryServiceImplTest {
 
@@ -36,21 +43,40 @@ public void testListAllCategory() throws WxErrorException {
     CategoryQualificationResponse response = categoryService.listAllCategory();
     assertNotNull(response);
     assertTrue(response.isSuccess());
-    System.out.println(response);
+    //System.out.println(response);
+    // 测试分类：7231 瑜伽服上衣
+    for (CategoryAndQualificationList cat : response.getCatsV2()) {
+      if (cat.getList() == null) {
+        continue;
+      }
+      for (CategoryQualification qua : cat.getList()) {
+        if (qua.getCategory() == null) {
+          log.error("category is null");
+        }
+        if ("7231".equals(qua.getCategory().getId())) {
+          log.info("qua: {}", JsonUtils.encode(qua));
+        }
+      }
+    }
   }
 
   @Test
-  public void testListAvailableCategory() throws WxErrorException {
+  public void testListAvailableCategories() throws WxErrorException {
     WxChannelCategoryService categoryService = channelService.getCategoryService();
-    List<ShopCategory> shopCategories = categoryService.listAvailableCategory("0");
-    assertTrue(CollectionUtils.hasElements(shopCategories));
-    shopCategories.forEach(System.out::println);
+    ShopCategoryResponse response = categoryService.listAvailableCategories("0");
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    List<ShopCategory> v1 = response.getCategories();
+    List<ShopCategory> v2 = response.getCatListV2();
+    assertTrue(CollectionUtils.hasElements(v1) || CollectionUtils.hasElements(v2));
+    v1.forEach(System.out::println);
+    v2.forEach(System.out::println);
   }
 
   @Test
   public void testGetCategoryDetail() throws WxErrorException {
     WxChannelCategoryService categoryService = channelService.getCategoryService();
-    CategoryDetailResult categoryDetail = categoryService.getCategoryDetail("1602");
+    CategoryDetailResult categoryDetail = categoryService.getCategoryDetail("7231");
     assertNotNull(categoryDetail);
     assertTrue(categoryDetail.isSuccess());
     System.out.println(categoryDetail);
@@ -58,11 +84,47 @@ public void testGetCategoryDetail() throws WxErrorException {
 
   @Test
   public void testAddCategory() throws WxErrorException {
+//    WxChannelCategoryService categoryService = channelService.getCategoryService();
+//    List<String> certificates = new ArrayList<>();
+//    certificates.add(
+//      "hWNith8iZSrxfN7W2tXOoWSXYWi1qADRJxwImvQl2DC6wqqJrl4g8i/UEZfd59yiiEKAnqy0WETFrOcGZFcJDfpH2ccmNZddzesR1/OpAC7bbfmEiDFBK2QL7MBjhR2m");
+//    AuditApplyResponse response = categoryService.addCategory("1001", "1002", "1005", certificates);
+//    assertNotNull(response);
+//    assertTrue(response.isSuccess());
+//    System.out.println(response);
+    String json = "{\n"
+      + "    \"category_info\": {\n"
+      + "        \"cats_v2\":[\n"
+      + "          {\n"
+      + "            \"cat_id\": 6033\n"
+      + "          },\n"
+      + "          {\n"
+      + "            \"cat_id\": 6057\n"
+      + "          },\n"
+      + "          {\n"
+      + "            \"cat_id\": 6091\n"
+      + "          },\n"
+      + "          {\n"
+      + "            \"cat_id\": 6093\n"
+      + "          }\n"
+      + "        ],\n"
+      + "        \"certificate\": [\n"
+      + "            \"THE_FILE_ID_1\",\n"
+      + "            \"THE_FILE_ID_2\"\n"
+      + "        ],\n"
+      + "        \"brand_list\" : [\n"
+      + "            { \"brand_id\": 1001 },\n"
+      + "            { \"brand_id\": 1002 }\n"
+      + "        ]\n"
+      + "    }\n"
+      + "}";
+    CategoryAuditRequest param = JsonUtils.decode(json, CategoryAuditRequest.class);
+    CategoryAuditInfo info = null;
+    if (info != null) {
+      info = param.getCategoryInfo();
+    }
     WxChannelCategoryService categoryService = channelService.getCategoryService();
-    List<String> certificates = new ArrayList<>();
-    certificates.add(
-      "hWNith8iZSrxfN7W2tXOoWSXYWi1qADRJxwImvQl2DC6wqqJrl4g8i/UEZfd59yiiEKAnqy0WETFrOcGZFcJDfpH2ccmNZddzesR1/OpAC7bbfmEiDFBK2QL7MBjhR2m");
-    AuditApplyResponse response = categoryService.addCategory("1001", "1002", "1005", certificates);
+    AuditApplyResponse response = categoryService.addCategory(info);
     assertNotNull(response);
     assertTrue(response.isSuccess());
     System.out.println(response);
diff --git a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelCompassShopServiceImplTest.java b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelCompassShopServiceImplTest.java
new file mode 100644
index 0000000000..cae4d23067
--- /dev/null
+++ b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelCompassShopServiceImplTest.java
@@ -0,0 +1,125 @@
+package me.chanjar.weixin.channel.api.impl;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import com.google.inject.Inject;
+import me.chanjar.weixin.channel.api.WxChannelCompassShopService;
+import me.chanjar.weixin.channel.api.WxChannelService;
+import me.chanjar.weixin.channel.bean.compass.shop.FinderAuthListResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.FinderListResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.FinderOverallResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.FinderProductListResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.FinderProductOverallResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.ShopLiveListResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.ShopOverallResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.ShopProductDataResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.ShopProductListResponse;
+import me.chanjar.weixin.channel.bean.compass.shop.ShopSaleProfileDataResponse;
+import me.chanjar.weixin.channel.test.ApiTestModule;
+import me.chanjar.weixin.common.error.WxErrorException;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+/**
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Guice(modules = ApiTestModule.class)
+public class WxChannelCompassShopServiceImplTest {
+
+  @Inject
+  private WxChannelService channelService;
+
+  @Test
+  public void testGetShopOverall() throws WxErrorException {
+    WxChannelCompassShopService service = channelService.getCompassShopService();
+    String ds = "20240306";
+    ShopOverallResponse response = service.getShopOverall(ds);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+  }
+
+  @Test
+  public void testGetFinderAuthorizationList() throws WxErrorException {
+    WxChannelCompassShopService service = channelService.getCompassShopService();
+    FinderAuthListResponse response = service.getFinderAuthorizationList();
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+  }
+
+  @Test
+  public void testGetFinderList() throws WxErrorException {
+    WxChannelCompassShopService service = channelService.getCompassShopService();
+    String ds = "20240306";
+    FinderListResponse response = service.getFinderList(ds);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+  }
+
+  @Test
+  public void testGetFinderOverall() throws WxErrorException {
+    WxChannelCompassShopService service = channelService.getCompassShopService();
+    String ds = "20240306";
+    FinderOverallResponse response = service.getFinderOverall(ds);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+  }
+
+  @Test
+  public void testGetFinderProductList() throws WxErrorException {
+    WxChannelCompassShopService service = channelService.getCompassShopService();
+    String ds = "";
+    String finderId = "";
+    FinderProductListResponse response = service.getFinderProductList(ds, finderId);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+  }
+
+  @Test
+  public void testGetFinderProductOverall() throws WxErrorException {
+    WxChannelCompassShopService service = channelService.getCompassShopService();
+    String ds = "";
+    String finderId = "";
+    FinderProductOverallResponse response = service.getFinderProductOverall(ds, finderId);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+  }
+
+  @Test
+  public void testGetShopLiveList() throws WxErrorException {
+    WxChannelCompassShopService service = channelService.getCompassShopService();
+    String ds = "";
+    String finderId = "";
+    ShopLiveListResponse response = service.getShopLiveList(ds, finderId);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+  }
+
+  @Test
+  public void testGetShopProductData() throws WxErrorException {
+    WxChannelCompassShopService service = channelService.getCompassShopService();
+    String ds = "20240306";
+    String productId = "";
+    ShopProductDataResponse response = service.getShopProductData(ds, productId);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+  }
+
+  @Test
+  public void testGetShopProductList() throws WxErrorException {
+    WxChannelCompassShopService service = channelService.getCompassShopService();
+    String ds = "20240306";
+    ShopProductListResponse response = service.getShopProductList(ds);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+  }
+
+  @Test
+  public void testGetShopSaleProfileData() throws WxErrorException {
+    WxChannelCompassShopService service = channelService.getCompassShopService();
+    String ds = "20240306";
+    ShopSaleProfileDataResponse response = service.getShopSaleProfileData(ds, 3);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+  }
+}
diff --git a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelOrderServiceImplTest.java b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelOrderServiceImplTest.java
index 2eb14b062e..2c70c7bde8 100644
--- a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelOrderServiceImplTest.java
+++ b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelOrderServiceImplTest.java
@@ -12,13 +12,17 @@
 import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
 import me.chanjar.weixin.channel.bean.delivery.DeliveryCompanyResponse;
 import me.chanjar.weixin.channel.bean.delivery.DeliveryInfo;
+import me.chanjar.weixin.channel.bean.delivery.PackageAuditInfo;
 import me.chanjar.weixin.channel.bean.order.ChangeOrderInfo;
+import me.chanjar.weixin.channel.bean.order.DecodeSensitiveInfoResponse;
 import me.chanjar.weixin.channel.bean.order.DeliveryUpdateParam;
 import me.chanjar.weixin.channel.bean.order.OrderAddressInfo;
 import me.chanjar.weixin.channel.bean.order.OrderInfoResponse;
 import me.chanjar.weixin.channel.bean.order.OrderListParam;
 import me.chanjar.weixin.channel.bean.order.OrderListResponse;
+import me.chanjar.weixin.channel.bean.order.OrderSearchCondition;
 import me.chanjar.weixin.channel.bean.order.OrderSearchParam;
+import me.chanjar.weixin.channel.bean.order.VirtualTelNumberResponse;
 import me.chanjar.weixin.channel.test.ApiTestModule;
 import me.chanjar.weixin.common.error.WxErrorException;
 import org.testng.annotations.Guice;
@@ -42,6 +46,16 @@ public void testGetOrder() throws WxErrorException {
     assertTrue(response.isSuccess());
   }
 
+  @Test
+  public void testGetOrder2() throws WxErrorException {
+    WxChannelOrderService orderService = channelService.getOrderService();
+    String orderId = "";
+    boolean encodeSensitiveInfo = true;
+    OrderInfoResponse response = orderService.getOrder(orderId, encodeSensitiveInfo);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+  }
+
   @Test
   public void testGetOrders() throws WxErrorException {
     WxChannelOrderService orderService = channelService.getOrderService();
@@ -55,6 +69,10 @@ public void testGetOrders() throws WxErrorException {
   public void testSearchOrder() throws WxErrorException {
     WxChannelOrderService orderService = channelService.getOrderService();
     OrderSearchParam param = new OrderSearchParam();
+    param.setPageSize(100);
+    OrderSearchCondition searchCondition = new OrderSearchCondition();
+    searchCondition.setTitle("");
+    param.setSearchCondition(searchCondition);
     OrderListResponse response = orderService.searchOrder(param);
     assertNotNull(response);
     assertTrue(response.isSuccess());
@@ -132,7 +150,7 @@ public void testCloseOrder() {
   @Test
   public void testListDeliveryCompany() throws WxErrorException {
     WxChannelOrderService orderService = channelService.getOrderService();
-    DeliveryCompanyResponse response = orderService.listDeliveryCompany();
+    DeliveryCompanyResponse response = orderService.listDeliveryCompany(false);
     assertNotNull(response);
     assertTrue(response.isSuccess());
   }
@@ -148,4 +166,36 @@ public void testDeliveryOrder() throws WxErrorException {
     assertNotNull(response);
     assertTrue(response.isSuccess());
   }
+
+  @Test
+  public void testUploadFreshInspect() throws WxErrorException {
+    WxChannelOrderService orderService = channelService.getOrderService();
+    String orderId = "123";
+    List<PackageAuditInfo> items = new ArrayList<>();
+    items.add(new PackageAuditInfo("product_express_pic_url", "https://store.mp.video.tencent-cloud.com/x"));
+    items.add(new PackageAuditInfo("product_packaging_box_panoramic_video_url", "https://store.mp.video.tencent-cloud.com/y"));
+    items.add(new PackageAuditInfo("product_unboxing_panoramic_video_url", "https://store.mp.video.tencent-cloud.com/z"));
+    items.add(new PackageAuditInfo("single_product_detail_panoramic_video_url", "https://store.mp.video.tencent-cloud.com/a"));
+    WxChannelBaseResponse response = orderService.uploadFreshInspect(orderId, items);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+  }
+
+  @Test
+  public void testGetVirtualTelNumber() throws WxErrorException {
+    WxChannelOrderService orderService = channelService.getOrderService();
+    String orderId = "123";
+    VirtualTelNumberResponse response = orderService.getVirtualTelNumber(orderId);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+  }
+
+  @Test
+  public void testDecodeSensitiveInfo() throws WxErrorException {
+    WxChannelOrderService orderService = channelService.getOrderService();
+    String orderId = "123";
+    DecodeSensitiveInfoResponse response = orderService.decodeSensitiveInfo(orderId);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+  }
 }
diff --git a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelProductServiceImplTest.java b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelProductServiceImplTest.java
index b14bc9b3fc..ed83434ee0 100644
--- a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelProductServiceImplTest.java
+++ b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelProductServiceImplTest.java
@@ -4,17 +4,23 @@
 import static org.testng.Assert.assertTrue;
 
 import com.google.inject.Inject;
+import java.util.ArrayList;
+import java.util.List;
 import me.chanjar.weixin.channel.api.WxChannelProductService;
 import me.chanjar.weixin.channel.api.WxChannelService;
 import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
 import me.chanjar.weixin.channel.bean.limit.LimitTaskAddResponse;
 import me.chanjar.weixin.channel.bean.limit.LimitTaskListResponse;
 import me.chanjar.weixin.channel.bean.limit.LimitTaskParam;
+import me.chanjar.weixin.channel.bean.product.SkuStockBatchResponse;
 import me.chanjar.weixin.channel.bean.product.SkuStockResponse;
 import me.chanjar.weixin.channel.bean.product.SpuGetResponse;
-import me.chanjar.weixin.channel.bean.product.SpuInfo;
 import me.chanjar.weixin.channel.bean.product.SpuListResponse;
+import me.chanjar.weixin.channel.bean.product.SpuUpdateInfo;
 import me.chanjar.weixin.channel.bean.product.SpuUpdateResponse;
+import me.chanjar.weixin.channel.bean.product.link.ProductH5UrlResponse;
+import me.chanjar.weixin.channel.bean.product.link.ProductQrCodeResponse;
+import me.chanjar.weixin.channel.bean.product.link.ProductTagLinkResponse;
 import me.chanjar.weixin.channel.test.ApiTestModule;
 import me.chanjar.weixin.common.error.WxErrorException;
 import org.testng.annotations.Guice;
@@ -32,7 +38,7 @@ public class WxChannelProductServiceImplTest {
   @Test
   public void testAddProduct() throws WxErrorException {
     WxChannelProductService productService = channelService.getProductService();
-    SpuInfo spuInfo = new SpuInfo();
+    SpuUpdateInfo spuInfo = new SpuUpdateInfo();
     // ...
     SpuUpdateResponse response = productService.addProduct(spuInfo);
     assertNotNull(response);
@@ -42,7 +48,7 @@ public void testAddProduct() throws WxErrorException {
   @Test
   public void testUpdateProduct() throws WxErrorException {
     WxChannelProductService productService = channelService.getProductService();
-    SpuInfo spuInfo = new SpuInfo();
+    SpuUpdateInfo spuInfo = new SpuUpdateInfo();
     // ...
     SpuUpdateResponse response = productService.updateProduct(spuInfo);
     assertNotNull(response);
@@ -121,13 +127,53 @@ public void testDownProduct() throws WxErrorException {
   @Test
   public void testGetSkuStock() throws WxErrorException {
     WxChannelProductService productService = channelService.getProductService();
-    String productId = "";
-    String skuId = "";
+    String productId = "10000076089602";
+    String skuId = "1918289111";
     SkuStockResponse response = productService.getSkuStock(productId, skuId);
     assertNotNull(response);
     assertTrue(response.isSuccess());
   }
 
+  @Test
+  public void testGetSkuStockBatch() throws WxErrorException {
+    WxChannelProductService productService = channelService.getProductService();
+    List<String> productIds = new ArrayList<>();
+    productIds.add("123");
+    SkuStockBatchResponse response = productService.getSkuStockBatch(productIds);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+  }
+
+  @Test
+  public void testGetProductH5Url() throws WxErrorException {
+    WxChannelProductService productService = channelService.getProductService();
+    String productId = "";
+    ProductH5UrlResponse response = productService.getProductH5Url(productId);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    System.out.println(response.getProductH5url());
+  }
+
+  @Test
+  public void testGetProductQrCode() throws WxErrorException {
+    WxChannelProductService productService = channelService.getProductService();
+    String productId = "";
+    ProductQrCodeResponse response = productService.getProductQrCode(productId);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    System.out.println(response.getProductQrcode());
+  }
+
+  @Test
+  public void testGetProductTagLink() throws WxErrorException {
+    WxChannelProductService productService = channelService.getProductService();
+    String productId = "";
+    ProductTagLinkResponse response = productService.getProductTagLink(productId);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    System.out.println(response.getProductTaglink());
+  }
+
   @Test
   public void testAddLimitTask() throws WxErrorException {
     WxChannelProductService productService = channelService.getProductService();
diff --git a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelVipServiceImplTest.java b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelVipServiceImplTest.java
new file mode 100644
index 0000000000..fdcf599e90
--- /dev/null
+++ b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxChannelVipServiceImplTest.java
@@ -0,0 +1,32 @@
+package me.chanjar.weixin.channel.api.impl;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import com.google.inject.Inject;
+import me.chanjar.weixin.channel.api.WxChannelService;
+import me.chanjar.weixin.channel.bean.vip.VipInfoResponse;
+import me.chanjar.weixin.channel.test.ApiTestModule;
+import me.chanjar.weixin.channel.util.JsonUtils;
+import me.chanjar.weixin.common.error.WxErrorException;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+/**
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Guice(modules = ApiTestModule.class)
+public class WxChannelVipServiceImplTest {
+  @Inject
+  private WxChannelService channelService;
+
+  @Test
+  public void getVipInfo() throws WxErrorException {
+    String openId = "";
+    Boolean needPhoneNumber = false;
+    VipInfoResponse response = channelService.getVipService().getVipInfo(openId, needPhoneNumber);
+    System.out.println(JsonUtils.encode(response));
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+  }
+}
diff --git a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxStoreCooperationServiceImplTest.java b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxStoreCooperationServiceImplTest.java
new file mode 100644
index 0000000000..bf70ce3c78
--- /dev/null
+++ b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxStoreCooperationServiceImplTest.java
@@ -0,0 +1,66 @@
+package me.chanjar.weixin.channel.api.impl;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import com.google.inject.Inject;
+import me.chanjar.weixin.channel.api.WxChannelService;
+import me.chanjar.weixin.channel.api.WxStoreCooperationService;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+import me.chanjar.weixin.channel.test.ApiTestModule;
+import me.chanjar.weixin.channel.util.JsonUtils;
+import me.chanjar.weixin.common.error.WxErrorException;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+/**
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Guice(modules = ApiTestModule.class)
+public class WxStoreCooperationServiceImplTest {
+
+  @Inject
+  private WxChannelService channelService;
+
+  @Test
+  public void testListCooperation() throws WxErrorException {
+    WxStoreCooperationService service = channelService.getCooperationService();
+    Integer sharerType = 3;
+    WxChannelBaseResponse response = service.listCooperation(sharerType);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    System.out.println(JsonUtils.encode(response));
+  }
+
+  @Test
+  public void testGetCooperationStatus() throws WxErrorException {
+    WxStoreCooperationService service = channelService.getCooperationService();
+    WxChannelBaseResponse response = service.getCooperationStatus("sph3FZbOEY64mWQ", 2);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+  }
+
+  @Test
+  public void testGenerateQrCode() throws WxErrorException {
+    WxStoreCooperationService service = channelService.getCooperationService();
+    WxChannelBaseResponse response = service.generateQrCode("sph3FZbOEY64mWQ", 2);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+  }
+
+  @Test
+  public void testCancelInvitation() throws WxErrorException {
+    WxStoreCooperationService service = channelService.getCooperationService();
+    WxChannelBaseResponse response = service.cancelInvitation("sph3FZbOEY64mWQ", 2);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+  }
+
+  @Test
+  public void testUnbind() throws WxErrorException {
+    WxStoreCooperationService service = channelService.getCooperationService();
+    WxChannelBaseResponse response = service.unbind("sph3FZbOEY64mWQ", 2);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+  }
+}
diff --git a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxStoreHomePageServiceImplTest.java b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxStoreHomePageServiceImplTest.java
new file mode 100644
index 0000000000..0d6bb8c479
--- /dev/null
+++ b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/api/impl/WxStoreHomePageServiceImplTest.java
@@ -0,0 +1,339 @@
+package me.chanjar.weixin.channel.api.impl;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import com.google.inject.Inject;
+import me.chanjar.weixin.channel.api.WxStoreHomePageService;
+import me.chanjar.weixin.channel.api.WxChannelService;
+import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
+import me.chanjar.weixin.channel.bean.home.background.BackgroundApplyResponse;
+import me.chanjar.weixin.channel.bean.home.background.BackgroundGetResponse;
+import me.chanjar.weixin.channel.bean.home.banner.BannerApplyParam;
+import me.chanjar.weixin.channel.bean.home.banner.BannerApplyResponse;
+import me.chanjar.weixin.channel.bean.home.banner.BannerGetResponse;
+import me.chanjar.weixin.channel.bean.home.banner.BannerInfo;
+import me.chanjar.weixin.channel.bean.home.tree.TreeProductEditInfo;
+import me.chanjar.weixin.channel.bean.home.tree.TreeProductEditParam;
+import me.chanjar.weixin.channel.bean.home.tree.TreeProductListInfo;
+import me.chanjar.weixin.channel.bean.home.tree.TreeProductListResponse;
+import me.chanjar.weixin.channel.bean.home.tree.TreeShowGetResponse;
+import me.chanjar.weixin.channel.bean.home.tree.TreeShowInfo;
+import me.chanjar.weixin.channel.bean.home.tree.TreeShowParam;
+import me.chanjar.weixin.channel.bean.home.tree.TreeShowSetResponse;
+import me.chanjar.weixin.channel.bean.home.window.WindowProductSettingResponse;
+import me.chanjar.weixin.channel.test.ApiTestModule;
+import me.chanjar.weixin.channel.util.JsonUtils;
+import me.chanjar.weixin.common.error.WxErrorException;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+/**
+ * @author <a href="https://github.com/lixize">Zeyes</a>
+ */
+@Guice(modules = ApiTestModule.class)
+public class WxStoreHomePageServiceImplTest {
+
+  @Inject
+  private WxChannelService channelService;
+
+  @Test
+  public void testAddTreeProduct() throws WxErrorException {
+    WxStoreHomePageService service = channelService.getHomePageService();
+    // https://developers.weixin.qq.com/doc/store/API/homepage/classification/addclassificationproduct.html
+    String json = "{\n"
+      + "  \"req\": {\n"
+      + "    \"level_1_id\": 10000046,\n"
+      + "    \"level_2_id\": 10000048,\n"
+      + "    \"product_ids\": [\n"
+      + "      10000076089602\n"
+      + "    ]\n"
+      + "  }\n"
+      + "}";
+    TreeProductEditParam param = JsonUtils.decode(json, TreeProductEditParam.class);
+    TreeProductEditInfo info = null;
+    if (param != null) {
+      info = param.getReq();
+    }
+    WxChannelBaseResponse response = service.addTreeProduct(info);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    assertNotNull(info);
+    System.out.println(JsonUtils.encode(response));
+  }
+
+  @Test
+  public void testDelTreeProduct() throws WxErrorException {
+    WxStoreHomePageService service = channelService.getHomePageService();
+    String json = "{\n"
+      + "  \"req\": {\n"
+      + "    \"level_1_id\": 1,\n"
+      + "    \"level_2_id\": 0,\n"
+      + "    \"product_ids\": [\n"
+      + "      123\n"
+      + "    ]\n"
+      + "  }\n"
+      + "}";
+    TreeProductEditParam param = JsonUtils.decode(json, TreeProductEditParam.class);
+    TreeProductEditInfo info = null;
+    if (param != null) {
+      info = param.getReq();
+    }
+    WxChannelBaseResponse response = service.delTreeProduct(info);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    assertNotNull(info);
+    System.out.println(JsonUtils.encode(response));
+  }
+
+  @Test
+  public void testGetTreeProductList() throws WxErrorException {
+    WxStoreHomePageService service = channelService.getHomePageService();
+    String pageContext = "";
+    TreeProductListInfo info = new TreeProductListInfo();
+    info.setLevel1Id(1);
+    info.setLevel2Id(2);
+    info.setPageSize(10);
+    info.setPageContext(pageContext);
+    TreeProductListResponse response = service.getTreeProductList(info);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    assertNotNull(info);
+    System.out.println(JsonUtils.encode(response));
+  }
+
+  @Test
+  public void testSetShowTree() throws WxErrorException {
+    WxStoreHomePageService service = channelService.getHomePageService();
+    // https://developers.weixin.qq.com/doc/store/API/homepage/classification/setclassificationtree.html
+    String json = "{\n"
+      + "  \"req\": {\n"
+      + "    \"version\": 121,\n"
+      + "    \"classification_id_deleted\": [\n"
+      + "      \"1.2\"\n"
+      + "    ],\n"
+      + "    \"tree\": {\n"
+      + "      \"level_1\": [\n"
+      + "        {\n"
+      + "          \"id\": 4,\n"
+      + "          \"name\": \"测试7\",\n"
+      + "          \"level_2\": [\n"
+      + "            {\n"
+      + "              \"id\": 5,\n"
+      + "              \"name\": \"1\",\n"
+      + "              \"is_displayed\": 1\n"
+      + "            }\n"
+      + "          ],\n"
+      + "          \"is_displayed\": 1\n"
+      + "        },\n"
+      + "        {\n"
+      + "          \"id\": 6,\n"
+      + "          \"name\": \"测试8\",\n"
+      + "          \"level_2\": [\n"
+      + "            {\n"
+      + "              \"id\": 7,\n"
+      + "              \"name\": \"1\",\n"
+      + "              \"is_displayed\": 1\n"
+      + "            },\n"
+      + "            {\n"
+      + "              \"id\": 8,\n"
+      + "              \"name\": \"2\",\n"
+      + "              \"is_displayed\": 1\n"
+      + "            }\n"
+      + "          ],\n"
+      + "          \"is_displayed\": 1\n"
+      + "        }\n"
+      + "      ]\n"
+      + "    }\n"
+      + "  }\n"
+      + "}";
+    TreeShowParam param = JsonUtils.decode(json, TreeShowParam.class);
+    TreeShowInfo info = null;
+    if (param != null) {
+      info = param.getReq();
+    }
+    TreeShowSetResponse response = service.setShowTree(info);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    assertNotNull(info);
+    System.out.println(JsonUtils.encode(response));
+  }
+
+  @Test
+  public void testGetShowTree() throws WxErrorException {
+    WxStoreHomePageService service = channelService.getHomePageService();
+    TreeShowGetResponse response = service.getShowTree();
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    System.out.println(JsonUtils.encode(response));
+  }
+
+  @Test
+  public void testListWindowProduct() throws WxErrorException {
+    WxStoreHomePageService service = channelService.getHomePageService();
+    Integer pageSize = 1;
+    String nextKey = "";
+    WindowProductSettingResponse response = service.listWindowProduct(pageSize, nextKey);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    System.out.println(JsonUtils.encode(response));
+  }
+
+  @Test
+  public void testReorderWindowProduct() throws WxErrorException {
+    WxStoreHomePageService service = channelService.getHomePageService();
+    String productId = "";
+    Integer indexNum = 100;
+    WxChannelBaseResponse response = service.reorderWindowProduct(productId, indexNum);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    System.out.println(JsonUtils.encode(response));
+  }
+
+  @Test
+  public void testHideWindowProduct() throws WxErrorException {
+    WxStoreHomePageService service = channelService.getHomePageService();
+    String productId = "";
+    // 0:显示 1:隐藏
+    Integer setHide = 0;
+    WxChannelBaseResponse response = service.hideWindowProduct(productId, setHide);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    System.out.println(JsonUtils.encode(response));
+  }
+
+  @Test
+  public void testTopWindowProduct() throws WxErrorException {
+    WxStoreHomePageService service = channelService.getHomePageService();
+    String productId = "";
+    // 0:取消置顶 1:置顶
+    Integer setTop = 0;
+    WxChannelBaseResponse response = service.topWindowProduct(productId, setTop);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    System.out.println(JsonUtils.encode(response));
+  }
+
+  @Test
+  public void testApplyBackground() throws WxErrorException {
+    WxStoreHomePageService service = channelService.getHomePageService();
+    String imgUrl = "https://github.githubassets.com/images/icons/emoji/octocat.png";
+    BackgroundApplyResponse response = service.applyBackground(imgUrl);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    System.out.println(JsonUtils.encode(response));
+  }
+
+  @Test
+  public void testGetBackground() throws WxErrorException {
+    WxStoreHomePageService service = channelService.getHomePageService();
+    BackgroundGetResponse response = service.getBackground();
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    System.out.println(JsonUtils.encode(response));
+  }
+
+  @Test
+  public void testCancelBackground() throws WxErrorException {
+    Integer applyId = 1;
+    WxStoreHomePageService service = channelService.getHomePageService();
+    WxChannelBaseResponse response = service.cancelBackground(applyId);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    System.out.println(JsonUtils.encode(response));
+  }
+
+  @Test
+  public void testRemoveBackground() throws WxErrorException {
+    WxStoreHomePageService service = channelService.getHomePageService();
+    WxChannelBaseResponse response = service.removeBackground();
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    System.out.println(JsonUtils.encode(response));
+  }
+
+  @Test
+  public void testApplyBanner() throws WxErrorException {
+    WxStoreHomePageService service = channelService.getHomePageService();
+    // https://developers.weixin.qq.com/doc/store/API/homepage/banner/submit_banner_apply.html
+    String json = "{\n"
+      + "  \"banner\": {\n"
+      + "    \"scale\": 2,\n"
+      + "    \"banner\": [\n"
+      + "      {\n"
+      + "        \"type\": 1,\n"
+      + "        \"product\": {\n"
+      + "          \"product_id\": 123\n"
+      + "        },\n"
+      + "        \"banner\": {\n"
+      + "          \"description\": \"测试商品精品展示位描述\",\n"
+      + "          \"img_url\": \"https://store.mp.video.tencent-cloud.com/abc\",\n"
+      + "          \"title\": \"测试商品精品展示位标题\"\n"
+      + "        }\n"
+      + "      },\n"
+      + "      {\n"
+      + "        \"type\": 3,\n"
+      + "        \"finder\": {\n"
+      + "          \"feed_id\": \"export/abc\",\n"
+      + "          \"finder_user_name\": \"sphabc\"\n"
+      + "        },\n"
+      + "        \"banner\": {\n"
+      + "          \"description\": \"测试视频号视频精品展示位描述\",\n"
+      + "          \"img_url\": \"https://store.mp.video.tencent-cloud.com/abc\",\n"
+      + "          \"title\": \"测试视频号视频精品展示位标题\"\n"
+      + "        }\n"
+      + "      },\n"
+      + "      {\n"
+      + "        \"type\": 4,\n"
+      + "        \"official_account\": {\n"
+      + "          \"url\": \"https://mp.weixin.qq.com/abc\"\n"
+      + "        },\n"
+      + "        \"banner\": {\n"
+      + "          \"description\": \"测试公众号文章精品展示位描述\",\n"
+      + "          \"img_url\": \"https://store.mp.video.tencent-cloud.com/abc\",\n"
+      + "          \"title\": \"测试公众号文章精品展示位标题\"\n"
+      + "        }\n"
+      + "      }\n"
+      + "    ]\n"
+      + "  }\n"
+      + "}";
+    BannerApplyParam param = JsonUtils.decode(json, BannerApplyParam.class);
+    BannerInfo info = null;
+    if (param != null) {
+      info = param.getBanner();
+    }
+    BannerApplyResponse response = service.applyBanner(info);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    assertNotNull(info);
+    System.out.println(JsonUtils.encode(response));
+  }
+
+  @Test
+  public void testGetBanner() throws WxErrorException {
+    WxStoreHomePageService service = channelService.getHomePageService();
+    BannerGetResponse response = service.getBanner();
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    System.out.println(JsonUtils.encode(response));
+  }
+
+  @Test
+  public void testCancelBanner() throws WxErrorException {
+    Integer applyId = 1;
+    WxStoreHomePageService service = channelService.getHomePageService();
+    WxChannelBaseResponse response = service.cancelBanner(applyId);
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    System.out.println(JsonUtils.encode(response));
+  }
+
+  @Test
+  public void testRemoveBanner() throws WxErrorException {
+    WxStoreHomePageService service = channelService.getHomePageService();
+    WxChannelBaseResponse response = service.removeBanner();
+    assertNotNull(response);
+    assertTrue(response.isSuccess());
+    System.out.println(JsonUtils.encode(response));
+  }
+}
diff --git a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/message/WxChannelMessageRouterRuleTest.java b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/message/WxChannelMessageRouterRuleTest.java
index d1e2f72174..bff360f7cc 100644
--- a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/message/WxChannelMessageRouterRuleTest.java
+++ b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/message/WxChannelMessageRouterRuleTest.java
@@ -6,8 +6,7 @@
 import org.testng.annotations.Test;
 
 /**
- * @author LiXiZe
- * @since 2023-04-20
+ * @author <a href="https://github.com/lixize">Zeyes</a>
  */
 public class WxChannelMessageRouterRuleTest {
 
diff --git a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/message/WxChannelMessageRouterTest.java b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/message/WxChannelMessageRouterTest.java
index 755886fa4b..9d683edce6 100644
--- a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/message/WxChannelMessageRouterTest.java
+++ b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/message/WxChannelMessageRouterTest.java
@@ -1,7 +1,9 @@
 package me.chanjar.weixin.channel.message;
 
 import static me.chanjar.weixin.channel.constant.MessageEventConstants.BRAND;
+import static me.chanjar.weixin.channel.constant.MessageEventConstants.CLOSE_STORE;
 import static me.chanjar.weixin.channel.constant.MessageEventConstants.PRODUCT_SPU_AUDIT;
+import static me.chanjar.weixin.channel.constant.MessageEventConstants.SET_SHOP_NICKNAME;
 import static org.testng.Assert.*;
 
 import com.google.inject.Inject;
@@ -10,6 +12,8 @@
 import me.chanjar.weixin.channel.api.WxChannelService;
 import me.chanjar.weixin.channel.bean.message.product.BrandMessage;
 import me.chanjar.weixin.channel.bean.message.product.SpuAuditMessage;
+import me.chanjar.weixin.channel.bean.message.store.CloseStoreMessage;
+import me.chanjar.weixin.channel.bean.message.store.NicknameUpdateMessage;
 import me.chanjar.weixin.channel.message.rule.HandlerConsumer;
 import me.chanjar.weixin.channel.test.ApiTestModule;
 import me.chanjar.weixin.channel.util.JsonUtils;
@@ -18,8 +22,7 @@
 import org.testng.annotations.Test;
 
 /**
- * @author LiXiZe
- * @since 2023-04-21
+ * @author <a href="https://github.com/lixize">Zeyes</a>
  */
 @Slf4j
 @Guice(modules = ApiTestModule.class)
@@ -56,6 +59,48 @@ public void test1() {
     }
   }
 
+  @Test
+  public void closeStore() {
+    WxChannelMessageRouter router = new WxChannelMessageRouter();
+    /* 小店注销 */
+    this.addRule(router, CloseStoreMessage.class, CLOSE_STORE, this::closeStore);
+    /* 小店修改名称 */
+    this.addRule(router, NicknameUpdateMessage.class, SET_SHOP_NICKNAME, this::updateNickname);
+    String closeStoreJson = "{\n"
+      + "  \"ToUserName\": \"gh_*\",\n"
+      + "  \"FromUserName\": \"OPENID\",\n"
+      + "  \"CreateTime\": 1662480000,\n"
+      + "  \"MsgType\": \"event\",\n"
+      + "  \"Event\": \"channels_ec_close_store\",\n"
+      + "  \"appid\": \"APPID\",\n"
+      + "  \"close_timestamp\": \"1662480000\"\n"
+      + "}";
+    String updateNicknameJson = "{\n"
+      + "    \"ToUserName\": \"gh_*\", \n"
+      + "    \"FromUserName\": \"OPENID\", \n"
+      + "    \"CreateTime\": 1662480000, \n"
+      + "    \"MsgType\": \"event\", \n"
+      + "    \"Event\": \"set_shop_nickname\", \n"
+      + "    \"appid\": \"APPID\",\n"
+      + "    \"old_nickname\": \"旧昵称\",\n"
+      + "    \"new_nickname\": \"新昵称\"\n"
+      + "}";
+    WxChannelMessage message1 = JsonUtils.decode(closeStoreJson, WxChannelMessage.class);
+    WxChannelMessage message2 = JsonUtils.decode(updateNicknameJson, WxChannelMessage.class);
+    Object result1 = router.route(message1, closeStoreJson, "123456", channelService);
+    if (result1 != null) {
+      log.info("result1:{}", result1);
+    } else {
+      log.info("result1 return null");
+    }
+    Object result2 = router.route(message2, updateNicknameJson, "123456", channelService);
+    if (result2 != null) {
+      log.info("result2:{}", result2);
+    } else {
+      log.info("result2 return null");
+    }
+  }
+
   public void brandUpdate(BrandMessage message, String content, String appId,
     Map<String, Object> context, WxSessionManager sessionManager) {
     log.info("品牌更新:{}", JsonUtils.encode(message));
@@ -67,6 +112,16 @@ public void spuAudit(SpuAuditMessage message, String content, String appId,
     log.info("商品审核:{}", JsonUtils.encode(message));
   }
 
+  public void closeStore(CloseStoreMessage message, String content, String appId,
+    Map<String, Object> context, WxSessionManager sessionManager) {
+    log.info("小店注销:{}", JsonUtils.encode(message));
+  }
+
+  public void updateNickname(NicknameUpdateMessage message, String content, String appId,
+    Map<String, Object> context, WxSessionManager sessionManager) {
+    log.info("昵称更新:{}", JsonUtils.encode(message));
+  }
+
   /**
    * 添加一条规则进入路由器
    *
diff --git a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/test/ApiTestModule.java b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/test/ApiTestModule.java
index 8eba81a07e..ddfb3a4b8a 100644
--- a/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/test/ApiTestModule.java
+++ b/weixin-java-channel/src/test/java/me/chanjar/weixin/channel/test/ApiTestModule.java
@@ -29,6 +29,7 @@ public void configure(Binder binder) {
           "测试配置文件【" + TEST_CONFIG_XML + "】未找到，请参照test-config-sample.xml文件生成");
       }
 
+      // 提示xml相关依赖不存在时，引入一下就好
       TestConfig config = this.fromXml(TestConfig.class, inputStream);
       WxChannelService service = new WxChannelServiceImpl();
 
diff --git a/weixin-java-channel/src/test/resources/test-config.sample.xml b/weixin-java-channel/src/test/resources/test-config.sample.xml
index b04a50e5a7..b84d8d9109 100644
--- a/weixin-java-channel/src/test/resources/test-config.sample.xml
+++ b/weixin-java-channel/src/test/resources/test-config.sample.xml
@@ -4,6 +4,7 @@
   <secret>secret</secret>
   <token>Token</token>
   <aesKey>EncodingAESKey</aesKey>
+  <stableAccessToken>false</stableAccessToken>
   <accessToken>可以不填写</accessToken>
   <expiresTime>可以不填写</expiresTime>
 </xml>
diff --git a/weixin-java-common/pom.xml b/weixin-java-common/pom.xml
index ba6319a8d3..80cc01a84c 100644
--- a/weixin-java-common/pom.xml
+++ b/weixin-java-common/pom.xml
@@ -6,7 +6,7 @@
   <parent>
     <groupId>com.github.binarywang</groupId>
     <artifactId>wx-java</artifactId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
 
   <artifactId>weixin-java-common</artifactId>
@@ -24,6 +24,11 @@
       <artifactId>okhttp</artifactId>
       <scope>provided</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.httpcomponents.client5</groupId>
+      <artifactId>httpclient5</artifactId>
+      <scope>provided</scope>
+    </dependency>
 
     <dependency>
       <groupId>org.slf4j</groupId>
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java
index 60aeb1c427..20da30f586 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java
@@ -302,6 +302,7 @@ public static class EventType {
     public static final String VIEW = "VIEW";
     public static final String MASS_SEND_JOB_FINISH = "MASSSENDJOBFINISH";
 
+    public static final String SYS_APPROVAL_CHANGE = "sys_approval_change";
     /**
      * 扫码推事件的事件推送
      */
@@ -431,7 +432,7 @@ public static class EventType {
      */
     public static final String WEAPP_AUDIT_FAIL = "weapp_audit_fail";
 
-    
+
     /**
      * 小程序审核事件：审核延后
      */
@@ -622,4 +623,19 @@ public static class AppIdType {
      */
     public static final String MINI_TYPE = "mini";
   }
+
+  /**
+   * 新建文章类型
+   */
+  @UtilityClass
+  public static class ArticleType {
+    /**
+     * 图文消息
+     */
+    public static final String NEWS = "news";
+    /**
+     * 图片消息
+     */
+    public static final String NEWS_PIC = "newspic";
+  }
 }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMinishopImageUploadCustomizeResult.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMinishopImageUploadCustomizeResult.java
index cd700be7c1..5427d5cada 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMinishopImageUploadCustomizeResult.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMinishopImageUploadCustomizeResult.java
@@ -16,7 +16,7 @@ public class WxMinishopImageUploadCustomizeResult implements Serializable {
   private WxMinishopPicFileCustomizeResult imgInfo;
 
   public static WxMinishopImageUploadCustomizeResult fromJson(String json) {
-    JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject();
+    JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject();
     WxMinishopImageUploadCustomizeResult result = new WxMinishopImageUploadCustomizeResult();
     result.setErrcode(jsonObject.get(WxConsts.ERR_CODE).getAsNumber().toString());
     if (result.getErrcode().equals("0")) {
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMinishopImageUploadResult.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMinishopImageUploadResult.java
index 324232d0ee..9c2cbaf3ba 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMinishopImageUploadResult.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/bean/result/WxMinishopImageUploadResult.java
@@ -21,7 +21,7 @@ public class WxMinishopImageUploadResult  implements Serializable {
 
 
   public static WxMinishopImageUploadResult fromJson(String json) {
-    JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject();
+    JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject();
     WxMinishopImageUploadResult result = new WxMinishopImageUploadResult();
     result.setErrcode(jsonObject.get(WxConsts.ERR_CODE).getAsNumber().toString());
     if (result.getErrcode().equals("0")) {
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxChannelErrorMsgEnum.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxChannelErrorMsgEnum.java
new file mode 100644
index 0000000000..3491e74dc8
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxChannelErrorMsgEnum.java
@@ -0,0 +1,172 @@
+package me.chanjar.weixin.common.error;
+
+import com.google.common.collect.Maps;
+import java.util.Map;
+
+/**
+ *
+ * <pre>
+ *     微信小店公共错误码.
+ *     参考文档：<a href="https://developers.weixin.qq.com/doc/store/API/basics/commErrCode.html">微信小店公共错误码</a>
+ * </pre>
+ *
+ * @author Zeyes
+ */
+public enum WxChannelErrorMsgEnum {
+  /**
+   * 系统繁忙，此时请开发者稍候再试  system error
+   */
+  CODE_1(-1, "系统繁忙，此时请开发者稍候再试"),
+  /**
+   * 请求成功 ok
+   */
+  CODE_0(0, "请求成功"),
+  /**
+   * 获取 access_token 时 AppSecret 错误，或者 access_token 无效。请开发者认真检查 AppSecret 的正确性
+   * invalid credential, access_token is invalid or not latest, could get access_token by getStableAccessToken, more details at https://mmbizurl.cn/s/JtxxFh33r
+   */
+  CODE_40001(40001, "获取 access_token 时 AppSecret 错误，或者 access_token 无效。请开发者认真检查 AppSecret 的正确性"),
+  /**
+   * 请检查 openid 的正确性
+   * invalid openid
+   */
+  CODE_40003(40003, "请检查 openid 的正确性"),
+  /**
+   * 请检查 appid 的正确性，避免异常字符，注意大小写
+   * invalid appid
+   */
+  CODE_40013(40013, "请检查 appid 的正确性，避免异常字符，注意大小写"),
+  /**
+   * 请检查API的URL是否与文档一致
+   * invalid url
+   */
+  CODE_40066(40066, "请检查API的URL是否与文档一致"),
+  /**
+   * 缺少 access_token 参数
+   * access_token missing
+   */
+  CODE_41001(41001, "缺少 access_token 参数"),
+  /**
+   * 请检查URL参数中是否有 ?appid=
+   * appid missing
+   */
+  CODE_41002(41002, "请检查URL参数中是否有 ?appid="),
+  /**
+   * 请检查POST json中是否包含component_ appid宇段
+   * missing component_appid
+   */
+  CODE_41018(41018, "请检查POST json中是否包含component_ appid宇段"),
+  /**
+   * access_token失效，需要重新获取新的access_token
+   * access_token expired
+   */
+  CODE_42001(42001, "access_token失效，需要重新获取新的access_token"),
+  /**
+   * 请检查发起API请求的Method是否为POST
+   * require POST method
+   */
+  CODE_43002(43002, "请检查发起API请求的Method是否为POST"),
+  /**
+   * 请使用HTTPS方式清求，不要使用HTTP方式
+   * require https
+   */
+  CODE_43003(43003, "请使用HTTPS方式清求，不要使用HTTP方式"),
+  /**
+   * POST 的数据包为空
+   * empty post data
+   */
+  CODE_44002(44002, "POST 的数据包为空"),
+  /**
+   * 请对数据进行压缩
+   * content size out of limit
+   */
+  CODE_45002(45002, "请对数据进行压缩"),
+  /**
+   * 查看调用次数是否符合预期，可通过get_api_quota接口获取每天的调用quota；用完后可通过clear_quota进行清空
+   * reach max api daily quota limit
+   */
+  CODE_45009(45009, "查看调用次数是否符合预期，可通过get_api_quota接口获取每天的调用quota；用完后可通过clear_quota进行清空"),
+  /**
+   * 命中每分钟的频率限制
+   * api minute-quota reach limit must slower retry next minute
+   */
+  CODE_45011(45011, "命中每分钟的频率限制"),
+  /**
+   * 需要登录 channels.weixin.qq.com/shop 配置IP白名单
+   * access clientip is not registered, not in ip-white-list
+   */
+  CODE_45035(45035, "需要登录 channels.weixin.qq.com/shop 配置IP白名单"),
+  /**
+   * 解析 JSON/XML 内容错误
+   * data format error
+   */
+  CODE_47001(47001, "解析 JSON/XML 内容错误"),
+  /**
+   * 没有该接口权限
+   * api unauthorized
+   */
+  CODE_48001(48001, "没有该接口权限"),
+  /**
+   * 接口被禁用
+   * api forbidden for irregularities
+   */
+  CODE_48004(48004, "接口被禁用"),
+  /**
+   * 请找用户获取该api授权
+   * user unauthorized
+   */
+  CODE_50001(50001, "请找用户获取该api授权"),
+  /**
+   * 请检查封禁原因
+   * user limited
+   */
+  CODE_50002(50002, "请检查封禁原因"),
+  /**
+   * 需要登录 channels.weixin.qq.com/shop 配置IP白名单
+   * access clientip is not registered, not in ip-white-list
+   */
+  CODE_61004(61004, "需要登录 channels.weixin.qq.com/shop 配置IP白名单"),
+  /**
+   * 请检查第三方平台服务商检查已获取的授权集
+   * api is unauthorized to component
+   */
+  CODE_61007(61007, "请检查第三方平台服务商检查已获取的授权集"),
+  /**
+   * 需要登录 channels.weixin.qq.com/shop 继续完成注销
+   * 账号发起注销，进入注销公示期
+   */
+  CODE_10080000(10080000, "需要登录 channels.weixin.qq.com/shop 继续完成注销"),
+  /**
+   * 账号已注销
+   */
+  CODE_10080001(10080001, "账号已注销"),
+  /**
+   * 小店的视频号带货身份为达人号，不允许使用该功能，如需使用，请将带货身份修改为商家
+   */
+  CODE_10080002(10080002, "小店的视频号带货身份为达人号，不允许使用该功能，如需使用，请将带货身份修改为商家"),
+
+  ;
+
+  private final int code;
+  private final String msg;
+
+  WxChannelErrorMsgEnum(int code, String msg) {
+    this.code = code;
+    this.msg = msg;
+  }
+
+  static final Map<Integer, String> valueMap = Maps.newHashMap();
+
+  static {
+    for (WxChannelErrorMsgEnum value : WxChannelErrorMsgEnum.values()) {
+      valueMap.put(value.code, value.msg);
+    }
+  }
+
+  /**
+   * 通过错误代码查找其中文含义.
+   */
+  public static String findMsgByCode(int code) {
+    return valueMap.getOrDefault(code, null);
+  }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxError.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxError.java
index 1156636ea3..b45fba3411 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxError.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxError.java
@@ -91,6 +91,13 @@ public static WxError fromJson(String json, WxType type) {
         }
         break;
       }
+      case Channel: {
+        final String msg = WxChannelErrorMsgEnum.findMsgByCode(wxError.getErrorCode());
+        if (msg != null) {
+          wxError.setErrorMsg(msg);
+        }
+        break;
+      }
       default:
         return wxError;
     }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxMaErrorMsgEnum.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxMaErrorMsgEnum.java
index 46c1d3d3d2..1bb3f6472b 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxMaErrorMsgEnum.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/error/WxMaErrorMsgEnum.java
@@ -711,6 +711,132 @@ public enum WxMaErrorMsgEnum {
   CODE_89255(89255, "code参数无效，请检查code长度以及内容是否正确_；注意code_type的值不同需要传的code长度不一样 ；注意code_type的值不同需要传的code长度不一样"),
 
 //  CODE_504002(-504002, "云函数未找到 Function not found"),
+
+  /**
+   * 半屏小程序系统错误
+   */
+  CODE_89408(89408, "半屏小程序系统错误"),
+
+  /**
+   * 获取半屏小程序列表参数错误
+   */
+  CODE_89409(89409, "获取半屏小程序列表参数错误"),
+
+  /**
+   * 添加半屏小程序appid参数错误
+   */
+  CODE_89410(89410, "添加半屏小程序appid参数错误"),
+
+  /**
+   * 添加半屏小程序appid参数为空
+   */
+  CODE_89411(89411, "添加半屏小程序appid参数为空"),
+
+  /**
+   * 添加半屏小程序申请理由不得超过30个字
+   */
+  CODE_89412(89412, "添加半屏小程序申请理由不得超过30个字"),
+
+  /**
+   * 该小程序被申请次数已达24h限制
+   */
+  CODE_89413(89413, "该小程序被申请次数已达24h限制"),
+
+  /**
+   * 每天仅允许申请50次半屏小程序
+   */
+  CODE_89414(89414, "每天仅允许申请50次半屏小程序"),
+
+  /**
+   * 删除半屏小程序appid参数为空
+   */
+  CODE_89415(89415, "删除半屏小程序appid参数为空"),
+
+  /**
+   * 取消半屏小程序授权appid参数为空
+   */
+  CODE_89416(89416, "取消半屏小程序授权appid参数为空"),
+
+  /**
+   * 修改半屏小程序方式flag参数错误
+   */
+  CODE_89417(89417, "修改半屏小程序方式flag参数错误"),
+
+  /**
+   * 获取半屏小程序每日申请次数失败
+   */
+  CODE_89418(89418, "获取半屏小程序每日申请次数失败"),
+
+  /**
+   * 获取半屏小程序每日授权次数失败
+   */
+  CODE_89419(89419, "获取半屏小程序每日授权次数失败"),
+
+  /**
+   * 不支持添加个人主体小程序
+   */
+  CODE_89420(89420, "不支持添加个人主体小程序"),
+
+  /**
+   * 删除数据未找到
+   */
+  CODE_89421(89421, "删除数据未找到"),
+
+  /**
+   * 删除状态异常
+   */
+  CODE_89422(89422, "删除状态异常"),
+
+  /**
+   * 申请次数添加到达上限
+   */
+  CODE_89423(89423, "申请次数添加到达上限"),
+
+  /**
+   * 申请添加已超时
+   */
+  CODE_89425(89425, "申请添加已超时"),
+
+  /**
+   * 申请添加状态异常
+   */
+  CODE_89426(89426, "申请添加状态异常"),
+
+  /**
+   * 申请号和授权号相同
+   */
+  CODE_89427(89427, "申请号和授权号相同"),
+
+  /**
+   * 该小程序已申请，不允许重复添加
+   */
+  CODE_89428(89428, "该小程序已申请，不允许重复添加"),
+
+  /**
+   * 已到达同一小程序每日最多申请次数
+   */
+  CODE_89429(89429, "已到达同一小程序每日最多申请次数"),
+
+  /**
+   * 该小程序已设置自动拒绝申请
+   */
+  CODE_89430(89430, "该小程序已设置自动拒绝申请"),
+
+  /**
+   * 不支持此类型小程序
+   */
+  CODE_89431(89431, "不支持此类型小程序"),
+
+  /**
+   * 不是小程序
+   */
+  CODE_89432(89432, "不是小程序"),
+
+  /**
+   * 授权次数到达上限
+   */
+  CODE_89424(89424, "授权次数到达上限"),
+
   ;
 
   private final int code;
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutor.java
index 2c9a4d7526..a93cbe1e99 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutor.java
@@ -1,11 +1,15 @@
 package me.chanjar.weixin.common.executor;
 
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
 import me.chanjar.weixin.common.bean.CommonUploadParam;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.ResponseHandler;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import okhttp3.OkHttpClient;
 
 import java.io.IOException;
 
@@ -34,15 +38,19 @@ public void execute(String uri, CommonUploadParam data, ResponseHandler<String>
    * @param requestHttp 请求信息
    * @return 执行器
    */
-  @SuppressWarnings({"rawtypes", "unchecked"})
-  public static RequestExecutor<String, CommonUploadParam> create(RequestHttp requestHttp) {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<String, CommonUploadParam> create(RequestHttp<?, ?> requestHttp) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new CommonUploadRequestExecutorApacheImpl(requestHttp);
+        return new CommonUploadRequestExecutorApacheImpl(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp);
       case JODD_HTTP:
-        return new CommonUploadRequestExecutorJoddHttpImpl(requestHttp);
+        return new CommonUploadRequestExecutorJoddHttpImpl((RequestHttp<HttpConnectionProvider, ProxyInfo>) requestHttp);
       case OK_HTTP:
-        return new CommonUploadRequestExecutorOkHttpImpl(requestHttp);
+        return new CommonUploadRequestExecutorOkHttpImpl((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp);
+      case HTTP_COMPONENTS:
+        return new CommonUploadRequestExecutorHttpComponentsImpl(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp);
       default:
         throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorApacheImpl.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorApacheImpl.java
index 6a3c05dd21..7f19241cdb 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorApacheImpl.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorApacheImpl.java
@@ -8,10 +8,10 @@
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.ContentType;
 import org.apache.http.entity.mime.HttpMultipartMode;
@@ -28,8 +28,7 @@
  * @author <a href="https://www.sacoc.cn">广州跨界</a>
  * created on  2024/01/11
  */
-public class CommonUploadRequestExecutorApacheImpl
-  extends CommonUploadRequestExecutor<CloseableHttpClient, HttpHost> {
+public class CommonUploadRequestExecutorApacheImpl extends CommonUploadRequestExecutor<CloseableHttpClient, HttpHost> {
 
   public CommonUploadRequestExecutorApacheImpl(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
     super(requestHttp);
@@ -52,19 +51,15 @@ public String execute(String uri, CommonUploadParam param, WxType wxType) throws
         .build();
       httpPost.setEntity(entity);
     }
-    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
-      String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
-      if (responseContent == null || responseContent.isEmpty()) {
-        throw new WxErrorException(String.format("上传失败，服务器响应空 url:%s param:%s", uri, param));
-      }
-      WxError error = WxError.fromJson(responseContent, wxType);
-      if (error.getErrorCode() != 0) {
-        throw new WxErrorException(error);
-      }
-      return responseContent;
-    } finally {
-      httpPost.releaseConnection();
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    if (StringUtils.isEmpty(responseContent)) {
+      throw new WxErrorException(String.format("上传失败，服务器响应空 url:%s param:%s", uri, param));
     }
+    WxError error = WxError.fromJson(responseContent, wxType);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
+    }
+    return responseContent;
   }
 
   /**
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorHttpComponentsImpl.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorHttpComponentsImpl.java
new file mode 100644
index 0000000000..f79eaa49b8
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/executor/CommonUploadRequestExecutorHttpComponentsImpl.java
@@ -0,0 +1,75 @@
+package me.chanjar.weixin.common.executor;
+
+import lombok.Getter;
+import me.chanjar.weixin.common.bean.CommonUploadData;
+import me.chanjar.weixin.common.bean.CommonUploadParam;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
+import org.apache.hc.client5.http.entity.mime.InputStreamBody;
+import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Apache HttpComponents 通用文件上传器
+ */
+public class CommonUploadRequestExecutorHttpComponentsImpl extends CommonUploadRequestExecutor<CloseableHttpClient, HttpHost> {
+
+  public CommonUploadRequestExecutorHttpComponentsImpl(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
+
+  @Override
+  public String execute(String uri, CommonUploadParam param, WxType wxType) throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+    if (param != null) {
+      CommonUploadData data = param.getData();
+      InnerStreamBody part = new InnerStreamBody(data.getInputStream(), ContentType.DEFAULT_BINARY, data.getFileName(), data.getLength());
+      HttpEntity entity = MultipartEntityBuilder
+        .create()
+        .addPart(param.getName(), part)
+        .setMode(HttpMultipartMode.EXTENDED)
+        .build();
+      httpPost.setEntity(entity);
+    }
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    if (StringUtils.isEmpty(responseContent)) {
+      throw new WxErrorException(String.format("上传失败，服务器响应空 url:%s param:%s", uri, param));
+    }
+    WxError error = WxError.fromJson(responseContent, wxType);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
+    }
+    return responseContent;
+  }
+
+  /**
+   * 内部流 请求体
+   */
+  @Getter
+  public static class InnerStreamBody extends InputStreamBody {
+
+    private final long contentLength;
+
+    public InnerStreamBody(final InputStream in, final ContentType contentType, final String filename, long contentLength) {
+      super(in, contentType, filename);
+      this.contentLength = contentLength;
+    }
+  }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernApacheHttpRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernApacheHttpRequestExecutor.java
index 22cdab3f92..03bec013dd 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernApacheHttpRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernApacheHttpRequestExecutor.java
@@ -8,7 +8,6 @@
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.mime.HttpMultipartMode;
 import org.apache.http.entity.mime.MultipartEntityBuilder;
@@ -24,7 +23,7 @@
  * created on  2019/6/27 14:06
  */
 public class OcrDiscernApacheHttpRequestExecutor extends OcrDiscernRequestExecutor<CloseableHttpClient, HttpHost> {
-  public OcrDiscernApacheHttpRequestExecutor(RequestHttp requestHttp) {
+  public OcrDiscernApacheHttpRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
     super(requestHttp);
   }
 
@@ -43,15 +42,11 @@ public String execute(String uri, File file, WxType wxType) throws WxErrorExcept
         .build();
       httpPost.setEntity(entity);
     }
-    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
-      String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
-      WxError error = WxError.fromJson(responseContent, wxType);
-      if (error.getErrorCode() != 0) {
-        throw new WxErrorException(error);
-      }
-      return responseContent;
-    } finally {
-      httpPost.releaseConnection();
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, wxType);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
     }
+    return responseContent;
   }
 }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernHttpComponentsRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernHttpComponentsRequestExecutor.java
new file mode 100644
index 0000000000..2d02c965a8
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernHttpComponentsRequestExecutor.java
@@ -0,0 +1,46 @@
+package me.chanjar.weixin.common.requestexecuter.ocr;
+
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
+import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.File;
+import java.io.IOException;
+
+public class OcrDiscernHttpComponentsRequestExecutor extends OcrDiscernRequestExecutor<CloseableHttpClient, HttpHost> {
+  public OcrDiscernHttpComponentsRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
+
+  @Override
+  public String execute(String uri, File file, WxType wxType) throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+    if (file != null) {
+      HttpEntity entity = MultipartEntityBuilder
+        .create()
+        .addBinaryBody("file", file)
+        .setMode(HttpMultipartMode.EXTENDED)
+        .build();
+      httpPost.setEntity(entity);
+    }
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, wxType);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
+    }
+    return responseContent;
+  }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernRequestExecutor.java
index 870f77d2ed..542ab4a378 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/requestexecuter/ocr/OcrDiscernRequestExecutor.java
@@ -5,6 +5,8 @@
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.ResponseHandler;
+import org.apache.http.HttpHost;
+import org.apache.http.impl.client.CloseableHttpClient;
 
 import java.io.File;
 import java.io.IOException;
@@ -18,7 +20,7 @@
 public abstract class OcrDiscernRequestExecutor<H, P> implements RequestExecutor<String, File> {
   protected RequestHttp<H, P> requestHttp;
 
-  public OcrDiscernRequestExecutor(RequestHttp requestHttp) {
+  public OcrDiscernRequestExecutor(RequestHttp<H, P> requestHttp) {
     this.requestHttp = requestHttp;
   }
 
@@ -27,12 +29,17 @@ public void execute(String uri, File data, ResponseHandler<String> handler, WxTy
     handler.handle(this.execute(uri, data, wxType));
   }
 
-  public static RequestExecutor<String, File> create(RequestHttp requestHttp) {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<String, File> create(RequestHttp<?, ?> requestHttp) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new OcrDiscernApacheHttpRequestExecutor(requestHttp);
+        return new OcrDiscernApacheHttpRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp);
+      case HTTP_COMPONENTS:
+        return new OcrDiscernHttpComponentsRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp);
       default:
-        return null;
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/BeanUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/BeanUtils.java
index 73b6cff368..d3f8d00406 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/BeanUtils.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/BeanUtils.java
@@ -2,7 +2,6 @@
 
 import com.google.common.collect.Lists;
 import me.chanjar.weixin.common.annotation.Required;
-import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/DataUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/DataUtils.java
index 983d9a668f..b8fb42e0e9 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/DataUtils.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/DataUtils.java
@@ -1,5 +1,6 @@
 package me.chanjar.weixin.common.util;
 
+import org.apache.commons.lang3.RegExUtils;
 import org.apache.commons.lang3.StringUtils;
 
 /**
@@ -17,7 +18,7 @@ public class DataUtils {
   public static <E> E handleDataWithSecret(E data) {
     E dataForLog = data;
     if(data instanceof String && StringUtils.contains((String)data, "&secret=")){
-      dataForLog = (E) StringUtils.replaceAll((String)data,"&secret=\\w+&","&secret=******&");
+      dataForLog = (E) RegExUtils.replaceAll((String)data,"&secret=\\w+&","&secret=******&");
     }
     return dataForLog;
   }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/XmlUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/XmlUtils.java
index facf564e32..67faf319f4 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/XmlUtils.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/XmlUtils.java
@@ -65,7 +65,7 @@ private static Object element2MapOrString(Element element) {
     final List<String> names = names(nodes);
 
     // 判断节点下有无非文本节点(非Text和CDATA)，如无，直接取Text文本内容
-    if (names.size() < 1) {
+    if (names.isEmpty()) {
       return element.getText();
     }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java
index f02d087b7d..0a40d0e93c 100755
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/crypto/WxCryptUtil.java
@@ -1,6 +1,5 @@
 package me.chanjar.weixin.common.util.crypto;
 
-import com.google.common.base.CharMatcher;
 import lombok.AllArgsConstructor;
 import lombok.Data;
 import me.chanjar.weixin.common.error.WxRuntimeException;
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/BaseMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/BaseMediaDownloadRequestExecutor.java
index ed5ec17bc9..8304742524 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/BaseMediaDownloadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/BaseMediaDownloadRequestExecutor.java
@@ -1,13 +1,18 @@
 package me.chanjar.weixin.common.util.http;
 
-import java.io.File;
-import java.io.IOException;
-
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.apache.ApacheMediaDownloadRequestExecutor;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsMediaDownloadRequestExecutor;
 import me.chanjar.weixin.common.util.http.jodd.JoddHttpMediaDownloadRequestExecutor;
 import me.chanjar.weixin.common.util.http.okhttp.OkHttpMediaDownloadRequestExecutor;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import okhttp3.OkHttpClient;
+
+import java.io.File;
+import java.io.IOException;
 
 /**
  * 下载媒体文件请求执行器.
@@ -30,16 +35,21 @@ public void execute(String uri, String data, ResponseHandler<File> handler, WxTy
     handler.handle(this.execute(uri, data, wxType));
   }
 
-  public static RequestExecutor<File, String> create(RequestHttp requestHttp, File tmpDirFile) {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<File, String> create(RequestHttp<?, ?> requestHttp, File tmpDirFile) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new ApacheMediaDownloadRequestExecutor(requestHttp, tmpDirFile);
+        return new ApacheMediaDownloadRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp, tmpDirFile);
       case JODD_HTTP:
-        return new JoddHttpMediaDownloadRequestExecutor(requestHttp, tmpDirFile);
+        return new JoddHttpMediaDownloadRequestExecutor((RequestHttp<HttpConnectionProvider, ProxyInfo>) requestHttp, tmpDirFile);
       case OK_HTTP:
-        return new OkHttpMediaDownloadRequestExecutor(requestHttp, tmpDirFile);
+        return new OkHttpMediaDownloadRequestExecutor((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp, tmpDirFile);
+      case HTTP_COMPONENTS:
+        return new HttpComponentsMediaDownloadRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp, tmpDirFile);
       default:
-        return null;
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpType.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpClientType.java
similarity index 59%
rename from weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpType.java
rename to weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpClientType.java
index eff5907f7a..a4e22be9b4 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpType.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpClientType.java
@@ -3,17 +3,21 @@
 /**
  * Created by ecoolper on 2017/4/28.
  */
-public enum HttpType {
+public enum HttpClientType {
   /**
    * jodd-http.
    */
   JODD_HTTP,
   /**
-   * apache httpclient.
+   * apache httpclient 4.x.
    */
   APACHE_HTTP,
   /**
    * okhttp.
    */
-  OK_HTTP
+  OK_HTTP,
+  /**
+   * apache httpclient 5.x.
+   */
+  HTTP_COMPONENTS
 }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpResponseProxy.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpResponseProxy.java
index 11b1209460..e45294b503 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpResponseProxy.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/HttpResponseProxy.java
@@ -1,10 +1,10 @@
 package me.chanjar.weixin.common.util.http;
 
-import jodd.http.HttpResponse;
 import me.chanjar.weixin.common.error.WxErrorException;
-import okhttp3.Response;
-import org.apache.http.Header;
-import org.apache.http.client.methods.CloseableHttpResponse;
+import me.chanjar.weixin.common.util.http.apache.ApacheHttpResponseProxy;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsResponseProxy;
+import me.chanjar.weixin.common.util.http.jodd.JoddHttpResponseProxy;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpResponseProxy;
 
 import java.io.UnsupportedEncodingException;
 import java.net.URLDecoder;
@@ -14,68 +14,33 @@
 
 /**
  * <pre>
- * 三种http框架的response代理类，方便提取公共方法
+ * http 框架的 response 代理类，方便提取公共方法
  * Created by Binary Wang on 2017-8-3.
  * </pre>
  *
  * @author <a href="https://github.com/binarywang">Binary Wang</a>
  */
-public class HttpResponseProxy {
+public interface HttpResponseProxy {
 
-  private CloseableHttpResponse apacheHttpResponse;
-  private HttpResponse joddHttpResponse;
-  private Response okHttpResponse;
-
-  public HttpResponseProxy(CloseableHttpResponse apacheHttpResponse) {
-    this.apacheHttpResponse = apacheHttpResponse;
-  }
-
-  public HttpResponseProxy(HttpResponse joddHttpResponse) {
-    this.joddHttpResponse = joddHttpResponse;
+  static ApacheHttpResponseProxy from(org.apache.http.client.methods.CloseableHttpResponse response) {
+    return new ApacheHttpResponseProxy(response);
   }
 
-  public HttpResponseProxy(Response okHttpResponse) {
-    this.okHttpResponse = okHttpResponse;
-  }
-
-  public String getFileName() throws WxErrorException {
-    //由于对象只能由一个构造方法实现，因此三个response对象必定且只有一个不为空
-    if (this.apacheHttpResponse != null) {
-      return this.getFileName(this.apacheHttpResponse);
-    }
-
-    if (this.joddHttpResponse != null) {
-      return this.getFileName(this.joddHttpResponse);
-    }
-
-    if (this.okHttpResponse != null) {
-      return this.getFileName(this.okHttpResponse);
-    }
-
-    //cannot happen
-    return null;
+  static HttpComponentsResponseProxy from(org.apache.hc.client5.http.impl.classic.CloseableHttpResponse response) {
+    return new HttpComponentsResponseProxy(response);
   }
 
-  private String getFileName(CloseableHttpResponse response) throws WxErrorException {
-    Header[] contentDispositionHeader = response.getHeaders("Content-disposition");
-    if (contentDispositionHeader == null || contentDispositionHeader.length == 0) {
-      throw new WxErrorException("无法获取到文件名，Content-disposition为空");
-    }
-
-    return extractFileNameFromContentString(contentDispositionHeader[0].getValue());
+  static JoddHttpResponseProxy from(jodd.http.HttpResponse response) {
+    return new JoddHttpResponseProxy(response);
   }
 
-  private String getFileName(HttpResponse response) throws WxErrorException {
-    String content = response.header("Content-disposition");
-    return extractFileNameFromContentString(content);
+  static OkHttpResponseProxy from(okhttp3.Response response) {
+    return new OkHttpResponseProxy(response);
   }
 
-  private String getFileName(Response response) throws WxErrorException {
-    String content = response.header("Content-disposition");
-    return extractFileNameFromContentString(content);
-  }
+  String getFileName() throws WxErrorException;
 
-  public static String extractFileNameFromContentString(String content) throws WxErrorException {
+  static String extractFileNameFromContentString(String content) throws WxErrorException {
     if (content == null || content.isEmpty()) {
       throw new WxErrorException("无法获取到文件名，content为空");
     }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaInputStreamUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaInputStreamUploadRequestExecutor.java
index de4be21709..22c426ca54 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaInputStreamUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaInputStreamUploadRequestExecutor.java
@@ -1,11 +1,16 @@
 package me.chanjar.weixin.common.util.http;
 
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
 import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.apache.ApacheMediaInputStreamUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsMediaInputStreamUploadRequestExecutor;
 import me.chanjar.weixin.common.util.http.jodd.JoddHttpMediaInputStreamUploadRequestExecutor;
 import me.chanjar.weixin.common.util.http.okhttp.OkHttpMediaInputStreamUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import okhttp3.OkHttpClient;
 
 import java.io.IOException;
 
@@ -18,7 +23,7 @@
 public abstract class MediaInputStreamUploadRequestExecutor<H, P> implements RequestExecutor<WxMediaUploadResult, InputStreamData> {
   protected RequestHttp<H, P> requestHttp;
 
-  public MediaInputStreamUploadRequestExecutor(RequestHttp requestHttp) {
+  public MediaInputStreamUploadRequestExecutor(RequestHttp<H, P> requestHttp) {
     this.requestHttp = requestHttp;
   }
 
@@ -27,16 +32,21 @@ public void execute(String uri, InputStreamData data, ResponseHandler<WxMediaUpl
     handler.handle(this.execute(uri, data, wxType));
   }
 
-  public static RequestExecutor<WxMediaUploadResult, InputStreamData> create(RequestHttp requestHttp) {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<WxMediaUploadResult, InputStreamData> create(RequestHttp<?, ?> requestHttp) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new ApacheMediaInputStreamUploadRequestExecutor(requestHttp);
+        return new ApacheMediaInputStreamUploadRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp);
       case JODD_HTTP:
-        return new JoddHttpMediaInputStreamUploadRequestExecutor(requestHttp);
+        return new JoddHttpMediaInputStreamUploadRequestExecutor((RequestHttp<HttpConnectionProvider, ProxyInfo>) requestHttp);
       case OK_HTTP:
-        return new OkHttpMediaInputStreamUploadRequestExecutor(requestHttp);
+        return new OkHttpMediaInputStreamUploadRequestExecutor((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp);
+      case HTTP_COMPONENTS:
+        return new HttpComponentsMediaInputStreamUploadRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp);
       default:
-        return null;
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java
index 83d0c099b3..2d16e714e9 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaUploadRequestExecutor.java
@@ -1,13 +1,18 @@
 package me.chanjar.weixin.common.util.http;
 
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
 import me.chanjar.weixin.common.bean.CommonUploadParam;
 import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.service.WxService;
 import me.chanjar.weixin.common.util.http.apache.ApacheMediaUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsMediaUploadRequestExecutor;
 import me.chanjar.weixin.common.util.http.jodd.JoddHttpMediaUploadRequestExecutor;
 import me.chanjar.weixin.common.util.http.okhttp.OkHttpMediaUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import okhttp3.OkHttpClient;
 
 import java.io.File;
 import java.io.IOException;
@@ -25,7 +30,7 @@
 public abstract class MediaUploadRequestExecutor<H, P> implements RequestExecutor<WxMediaUploadResult, File> {
   protected RequestHttp<H, P> requestHttp;
 
-  public MediaUploadRequestExecutor(RequestHttp requestHttp) {
+  public MediaUploadRequestExecutor(RequestHttp<H, P> requestHttp) {
     this.requestHttp = requestHttp;
   }
 
@@ -34,16 +39,21 @@ public void execute(String uri, File data, ResponseHandler<WxMediaUploadResult>
     handler.handle(this.execute(uri, data, wxType));
   }
 
-  public static RequestExecutor<WxMediaUploadResult, File> create(RequestHttp requestHttp) {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<WxMediaUploadResult, File> create(RequestHttp<?, ?> requestHttp) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new ApacheMediaUploadRequestExecutor(requestHttp);
+        return new ApacheMediaUploadRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp);
       case JODD_HTTP:
-        return new JoddHttpMediaUploadRequestExecutor(requestHttp);
+        return new JoddHttpMediaUploadRequestExecutor((RequestHttp<HttpConnectionProvider, ProxyInfo>) requestHttp);
       case OK_HTTP:
-        return new OkHttpMediaUploadRequestExecutor(requestHttp);
+        return new OkHttpMediaUploadRequestExecutor((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp);
+      case HTTP_COMPONENTS:
+        return new HttpComponentsMediaUploadRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp);
       default:
-        return null;
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MinishopUploadRequestCustomizeExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MinishopUploadRequestCustomizeExecutor.java
index e94b2d8d6a..0e8684a1db 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MinishopUploadRequestCustomizeExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MinishopUploadRequestCustomizeExecutor.java
@@ -1,11 +1,16 @@
 package me.chanjar.weixin.common.util.http;
 
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
 import me.chanjar.weixin.common.bean.result.WxMinishopImageUploadCustomizeResult;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.apache.ApacheMinishopMediaUploadRequestCustomizeExecutor;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsMinishopMediaUploadRequestCustomizeExecutor;
 import me.chanjar.weixin.common.util.http.jodd.JoddHttpMinishopMediaUploadRequestCustomizeExecutor;
 import me.chanjar.weixin.common.util.http.okhttp.OkHttpMinishopMediaUploadRequestCustomizeExecutor;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import okhttp3.OkHttpClient;
 
 import java.io.File;
 import java.io.IOException;
@@ -16,13 +21,12 @@ public abstract class MinishopUploadRequestCustomizeExecutor<H, P> implements Re
   protected String uploadType;
   protected String imgUrl;
 
-  public MinishopUploadRequestCustomizeExecutor(RequestHttp requestHttp, String respType, String imgUrl) {
+  public MinishopUploadRequestCustomizeExecutor(RequestHttp<H, P> requestHttp, String respType, String imgUrl) {
     this.requestHttp = requestHttp;
     this.respType = respType;
     if (imgUrl == null || imgUrl.isEmpty()) {
       this.uploadType = "0";
-    }
-    else {
+    } else {
       this.uploadType = "1";
       this.imgUrl = imgUrl;
     }
@@ -33,16 +37,21 @@ public void execute(String uri, File data, ResponseHandler<WxMinishopImageUpload
     handler.handle(this.execute(uri, data, wxType));
   }
 
-  public static RequestExecutor<WxMinishopImageUploadCustomizeResult, File> create(RequestHttp requestHttp, String respType, String imgUrl) {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<WxMinishopImageUploadCustomizeResult, File> create(RequestHttp<?, ?> requestHttp, String respType, String imgUrl) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new ApacheMinishopMediaUploadRequestCustomizeExecutor(requestHttp, respType, imgUrl);
+        return new ApacheMinishopMediaUploadRequestCustomizeExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp, respType, imgUrl);
       case JODD_HTTP:
-        return new JoddHttpMinishopMediaUploadRequestCustomizeExecutor(requestHttp, respType, imgUrl);
+        return new JoddHttpMinishopMediaUploadRequestCustomizeExecutor((RequestHttp<HttpConnectionProvider, ProxyInfo>) requestHttp, respType, imgUrl);
       case OK_HTTP:
-        return new OkHttpMinishopMediaUploadRequestCustomizeExecutor(requestHttp, respType, imgUrl);
+        return new OkHttpMinishopMediaUploadRequestCustomizeExecutor((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp, respType, imgUrl);
+      case HTTP_COMPONENTS:
+        return new HttpComponentsMinishopMediaUploadRequestCustomizeExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp, respType, imgUrl);
       default:
-        return null;
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MinishopUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MinishopUploadRequestExecutor.java
index ee4608edf3..e6018a7791 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MinishopUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MinishopUploadRequestExecutor.java
@@ -1,11 +1,16 @@
 package me.chanjar.weixin.common.util.http;
 
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
 import me.chanjar.weixin.common.bean.result.WxMinishopImageUploadResult;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.apache.ApacheMinishopMediaUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsMinishopMediaUploadRequestExecutor;
 import me.chanjar.weixin.common.util.http.jodd.JoddHttpMinishopMediaUploadRequestExecutor;
 import me.chanjar.weixin.common.util.http.okhttp.OkHttpMinishopMediaUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import okhttp3.OkHttpClient;
 
 import java.io.File;
 import java.io.IOException;
@@ -13,7 +18,7 @@
 public abstract class MinishopUploadRequestExecutor<H, P> implements RequestExecutor<WxMinishopImageUploadResult, File> {
   protected RequestHttp<H, P> requestHttp;
 
-  public MinishopUploadRequestExecutor(RequestHttp requestHttp) {
+  public MinishopUploadRequestExecutor(RequestHttp<H, P> requestHttp) {
     this.requestHttp = requestHttp;
   }
 
@@ -22,16 +27,21 @@ public void execute(String uri, File data, ResponseHandler<WxMinishopImageUpload
     handler.handle(this.execute(uri, data, wxType));
   }
 
-  public static RequestExecutor<WxMinishopImageUploadResult, File> create(RequestHttp requestHttp) {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<WxMinishopImageUploadResult, File> create(RequestHttp<?, ?> requestHttp) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new ApacheMinishopMediaUploadRequestExecutor(requestHttp);
+        return new ApacheMinishopMediaUploadRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp);
       case JODD_HTTP:
-        return new JoddHttpMinishopMediaUploadRequestExecutor(requestHttp);
+        return new JoddHttpMinishopMediaUploadRequestExecutor((RequestHttp<HttpConnectionProvider, ProxyInfo>) requestHttp);
       case OK_HTTP:
-        return new OkHttpMinishopMediaUploadRequestExecutor(requestHttp);
+        return new OkHttpMinishopMediaUploadRequestExecutor((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp);
+      case HTTP_COMPONENTS:
+        return new HttpComponentsMinishopMediaUploadRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp);
       default:
-        return null;
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java
index b7bc850f8f..36be78b8ae 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestHttp.java
@@ -26,6 +26,6 @@ public interface RequestHttp<H, P> {
    *
    * @return HttpType
    */
-  HttpType getRequestType();
+  HttpClientType getRequestType();
 
 }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java
index 266fd226e7..a880a9323c 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimpleGetRequestExecutor.java
@@ -1,11 +1,16 @@
 package me.chanjar.weixin.common.util.http;
 
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.apache.ApacheSimpleGetRequestExecutor;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsSimpleGetRequestExecutor;
 import me.chanjar.weixin.common.util.http.jodd.JoddHttpSimpleGetRequestExecutor;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
 import me.chanjar.weixin.common.util.http.okhttp.OkHttpSimpleGetRequestExecutor;
+import okhttp3.OkHttpClient;
 
 import java.io.IOException;
 
@@ -27,16 +32,21 @@ public void execute(String uri, String data, ResponseHandler<String> handler, Wx
     handler.handle(this.execute(uri, data, wxType));
   }
 
+  @SuppressWarnings("unchecked")
   public static RequestExecutor<String, String> create(RequestHttp<?, ?> requestHttp) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new ApacheSimpleGetRequestExecutor(requestHttp);
+        return new ApacheSimpleGetRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp);
       case JODD_HTTP:
-        return new JoddHttpSimpleGetRequestExecutor(requestHttp);
+        return new JoddHttpSimpleGetRequestExecutor((RequestHttp<HttpConnectionProvider, ProxyInfo>) requestHttp);
       case OK_HTTP:
-        return new OkHttpSimpleGetRequestExecutor(requestHttp);
+        return new OkHttpSimpleGetRequestExecutor((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp);
+      case HTTP_COMPONENTS:
+        return new HttpComponentsSimpleGetRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp);
       default:
-        throw new IllegalArgumentException("非法请求参数");
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java
index 0366b156af..2cc086cd0f 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/SimplePostRequestExecutor.java
@@ -1,11 +1,16 @@
 package me.chanjar.weixin.common.util.http;
 
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.apache.ApacheSimplePostRequestExecutor;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsSimplePostRequestExecutor;
 import me.chanjar.weixin.common.util.http.jodd.JoddHttpSimplePostRequestExecutor;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
 import me.chanjar.weixin.common.util.http.okhttp.OkHttpSimplePostRequestExecutor;
+import okhttp3.OkHttpClient;
 import org.jetbrains.annotations.NotNull;
 
 import java.io.IOException;
@@ -18,7 +23,7 @@
 public abstract class SimplePostRequestExecutor<H, P> implements RequestExecutor<String, String> {
   protected RequestHttp<H, P> requestHttp;
 
-  public SimplePostRequestExecutor(RequestHttp requestHttp) {
+  public SimplePostRequestExecutor(RequestHttp<H, P> requestHttp) {
     this.requestHttp = requestHttp;
   }
 
@@ -28,16 +33,21 @@ public void execute(String uri, String data, ResponseHandler<String> handler, Wx
     handler.handle(this.execute(uri, data, wxType));
   }
 
-  public static RequestExecutor<String, String> create(RequestHttp requestHttp) {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<String, String> create(RequestHttp<?, ?> requestHttp) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new ApacheSimplePostRequestExecutor(requestHttp);
+        return new ApacheSimplePostRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp);
       case JODD_HTTP:
-        return new JoddHttpSimplePostRequestExecutor(requestHttp);
+        return new JoddHttpSimplePostRequestExecutor((RequestHttp<HttpConnectionProvider, ProxyInfo>) requestHttp);
       case OK_HTTP:
-        return new OkHttpSimplePostRequestExecutor(requestHttp);
+        return new OkHttpSimplePostRequestExecutor((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp);
+      case HTTP_COMPONENTS:
+        return new HttpComponentsSimplePostRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp);
       default:
-        throw new IllegalArgumentException("非法请求参数");
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheBasicResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheBasicResponseHandler.java
new file mode 100644
index 0000000000..a91fc383ca
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheBasicResponseHandler.java
@@ -0,0 +1,9 @@
+package me.chanjar.weixin.common.util.http.apache;
+
+import org.apache.http.impl.client.BasicResponseHandler;
+
+public class ApacheBasicResponseHandler extends BasicResponseHandler {
+
+  public static final ApacheBasicResponseHandler INSTANCE = new ApacheBasicResponseHandler();
+
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientBuilder.java
index 0d5073de14..de34ca5bd1 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientBuilder.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpClientBuilder.java
@@ -53,4 +53,10 @@ public interface ApacheHttpClientBuilder {
    * ssl连接socket工厂.
    */
   ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory);
+
+  /**
+   * 支持的TLS协议版本.
+   * Supported TLS protocol versions.
+   */
+  ApacheHttpClientBuilder supportedProtocols(String[] supportedProtocols);
 }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java
index 6a136600e5..b3ebf350be 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpDnsClientBuilder.java
@@ -117,6 +117,13 @@ public ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFac
     return this;
   }
 
+  @Override
+  public ApacheHttpClientBuilder supportedProtocols(String[] supportedProtocols) {
+    // This implementation doesn't use the supportedProtocols parameter as it relies on the provided SSLConnectionSocketFactory
+    // Users should configure the SSLConnectionSocketFactory with desired protocols before setting it
+    return this;
+  }
+
   /**
    * 获取链接的超时时间设置,默认3000ms
    * <p>
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpResponseProxy.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpResponseProxy.java
new file mode 100644
index 0000000000..06439d3879
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheHttpResponseProxy.java
@@ -0,0 +1,25 @@
+package me.chanjar.weixin.common.util.http.apache;
+
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.HttpResponseProxy;
+import org.apache.http.Header;
+import org.apache.http.client.methods.CloseableHttpResponse;
+
+public class ApacheHttpResponseProxy implements HttpResponseProxy {
+
+  private final CloseableHttpResponse httpResponse;
+
+  public ApacheHttpResponseProxy(CloseableHttpResponse closeableHttpResponse) {
+    this.httpResponse = closeableHttpResponse;
+  }
+
+  @Override
+  public String getFileName() throws WxErrorException {
+    Header[] contentDispositionHeader = this.httpResponse.getHeaders("Content-disposition");
+    if (contentDispositionHeader == null || contentDispositionHeader.length == 0) {
+      throw new WxErrorException("无法获取到文件名，Content-disposition为空");
+    }
+
+    return HttpResponseProxy.extractFileNameFromContentString(contentDispositionHeader[0].getValue());
+  }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java
index e2f4611439..554dc8df7b 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaDownloadRequestExecutor.java
@@ -28,7 +28,7 @@
  * created on  2017/5/5
  */
 public class ApacheMediaDownloadRequestExecutor extends BaseMediaDownloadRequestExecutor<CloseableHttpClient, HttpHost> {
-  public ApacheMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) {
+  public ApacheMediaDownloadRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp, File tmpDirFile) {
     super(requestHttp, tmpDirFile);
   }
 
@@ -58,7 +58,7 @@ public File execute(String uri, String queryParam, WxType wxType) throws WxError
         }
       }
 
-      String fileName = new HttpResponseProxy(response).getFileName();
+      String fileName = HttpResponseProxy.from(response).getFileName();
       if (StringUtils.isBlank(fileName)) {
         fileName = String.valueOf(System.currentTimeMillis());
       }
@@ -68,11 +68,7 @@ public File execute(String uri, String queryParam, WxType wxType) throws WxError
         baseName = String.valueOf(System.currentTimeMillis());
       }
 
-      return FileUtils.createTmpFile(inputStream, baseName, FilenameUtils.getExtension(fileName),
-        super.tmpDirFile);
-
-    } finally {
-      httpGet.releaseConnection();
+      return FileUtils.createTmpFile(inputStream, baseName, FilenameUtils.getExtension(fileName), super.tmpDirFile);
     }
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaInputStreamUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaInputStreamUploadRequestExecutor.java
index ef09812cb2..43a5d604b0 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaInputStreamUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaInputStreamUploadRequestExecutor.java
@@ -10,7 +10,6 @@
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.ContentType;
 import org.apache.http.entity.mime.HttpMultipartMode;
@@ -26,7 +25,7 @@
  * created on  2022/02/15
  */
 public class ApacheMediaInputStreamUploadRequestExecutor extends MediaInputStreamUploadRequestExecutor<CloseableHttpClient, HttpHost> {
-  public ApacheMediaInputStreamUploadRequestExecutor(RequestHttp requestHttp) {
+  public ApacheMediaInputStreamUploadRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
     super(requestHttp);
   }
 
@@ -45,15 +44,11 @@ public WxMediaUploadResult execute(String uri, InputStreamData data, WxType wxTy
         .build();
       httpPost.setEntity(entity);
     }
-    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
-      String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
-      WxError error = WxError.fromJson(responseContent, wxType);
-      if (error.getErrorCode() != 0) {
-        throw new WxErrorException(error);
-      }
-      return WxMediaUploadResult.fromJson(responseContent);
-    } finally {
-      httpPost.releaseConnection();
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, wxType);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
     }
+    return WxMediaUploadResult.fromJson(responseContent);
   }
 }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaUploadRequestExecutor.java
index ca33b8641f..5d3eae174f 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaUploadRequestExecutor.java
@@ -1,7 +1,7 @@
 package me.chanjar.weixin.common.util.http.apache;
 
-import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
+import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
@@ -9,7 +9,6 @@
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.mime.HttpMultipartMode;
 import org.apache.http.entity.mime.MultipartEntityBuilder;
@@ -22,7 +21,7 @@
  * Created by ecoolper on 2017/5/5.
  */
 public class ApacheMediaUploadRequestExecutor extends MediaUploadRequestExecutor<CloseableHttpClient, HttpHost> {
-  public ApacheMediaUploadRequestExecutor(RequestHttp requestHttp) {
+  public ApacheMediaUploadRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
     super(requestHttp);
   }
 
@@ -41,15 +40,11 @@ public WxMediaUploadResult execute(String uri, File file, WxType wxType) throws
         .build();
       httpPost.setEntity(entity);
     }
-    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
-      String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
-      WxError error = WxError.fromJson(responseContent, wxType);
-      if (error.getErrorCode() != 0) {
-        throw new WxErrorException(error);
-      }
-      return WxMediaUploadResult.fromJson(responseContent);
-    } finally {
-      httpPost.releaseConnection();
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, wxType);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
     }
+    return WxMediaUploadResult.fromJson(responseContent);
   }
 }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMinishopMediaUploadRequestCustomizeExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMinishopMediaUploadRequestCustomizeExecutor.java
index 9af02af5d0..48fafc3401 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMinishopMediaUploadRequestCustomizeExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMinishopMediaUploadRequestCustomizeExecutor.java
@@ -10,7 +10,6 @@
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.mime.HttpMultipartMode;
 import org.apache.http.entity.mime.MultipartEntityBuilder;
@@ -24,7 +23,7 @@
  */
 @Slf4j
 public class ApacheMinishopMediaUploadRequestCustomizeExecutor extends MinishopUploadRequestCustomizeExecutor<CloseableHttpClient, HttpHost> {
-  public ApacheMinishopMediaUploadRequestCustomizeExecutor(RequestHttp requestHttp, String respType, String imgUrl) {
+  public ApacheMinishopMediaUploadRequestCustomizeExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp, String respType, String imgUrl) {
     super(requestHttp, respType, imgUrl);
   }
 
@@ -58,16 +57,12 @@ public WxMinishopImageUploadCustomizeResult execute(String uri, File file, WxTyp
               .build();
       httpPost.setEntity(entity);
     }
-    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
-      String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
-      WxError error = WxError.fromJson(responseContent, wxType);
-      if (error.getErrorCode() != 0) {
-        throw new WxErrorException(error);
-      }
-      log.info("responseContent: " + responseContent);
-      return WxMinishopImageUploadCustomizeResult.fromJson(responseContent);
-    } finally {
-      httpPost.releaseConnection();
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, wxType);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
     }
+    log.info("responseContent: {}", responseContent);
+    return WxMinishopImageUploadCustomizeResult.fromJson(responseContent);
   }
 }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMinishopMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMinishopMediaUploadRequestExecutor.java
index 7adc6a2cfa..f76d4e8642 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMinishopMediaUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMinishopMediaUploadRequestExecutor.java
@@ -5,13 +5,11 @@
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
 import me.chanjar.weixin.common.util.http.MinishopUploadRequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.mime.HttpMultipartMode;
 import org.apache.http.entity.mime.MultipartEntityBuilder;
@@ -25,7 +23,7 @@
  */
 @Slf4j
 public class ApacheMinishopMediaUploadRequestExecutor extends MinishopUploadRequestExecutor<CloseableHttpClient, HttpHost> {
-  public ApacheMinishopMediaUploadRequestExecutor(RequestHttp requestHttp) {
+  public ApacheMinishopMediaUploadRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
     super(requestHttp);
   }
 
@@ -44,16 +42,12 @@ public WxMinishopImageUploadResult execute(String uri, File file, WxType wxType)
         .build();
       httpPost.setEntity(entity);
     }
-    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
-      String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
-      WxError error = WxError.fromJson(responseContent, wxType);
-      if (error.getErrorCode() != 0) {
-        throw new WxErrorException(error);
-      }
-      log.info("responseContent: " + responseContent);
-      return WxMinishopImageUploadResult.fromJson(responseContent);
-    } finally {
-      httpPost.releaseConnection();
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, wxType);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
     }
+    log.info("responseContent: {}", responseContent);
+    return WxMinishopImageUploadResult.fromJson(responseContent);
   }
 }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimpleGetRequestExecutor.java
index be0784b076..08ccf1b252 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimpleGetRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimpleGetRequestExecutor.java
@@ -6,7 +6,6 @@
 import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.impl.client.CloseableHttpClient;
 
@@ -19,7 +18,7 @@
  * created on  2017/5/4
  */
 public class ApacheSimpleGetRequestExecutor extends SimpleGetRequestExecutor<CloseableHttpClient, HttpHost> {
-  public ApacheSimpleGetRequestExecutor(RequestHttp requestHttp) {
+  public ApacheSimpleGetRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
     super(requestHttp);
   }
 
@@ -37,12 +36,8 @@ public String execute(String uri, String queryParam, WxType wxType) throws WxErr
       httpGet.setConfig(config);
     }
 
-    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpGet)) {
-      String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
-      return handleResponse(wxType, responseContent);
-    } finally {
-      httpGet.releaseConnection();
-    }
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpGet, Utf8ResponseHandler.INSTANCE);
+    return handleResponse(wxType, responseContent);
   }
 
 }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimplePostRequestExecutor.java
index 52c8caaf3d..65af81690d 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimplePostRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheSimplePostRequestExecutor.java
@@ -4,15 +4,15 @@
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
-import org.apache.http.Consts;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.impl.client.CloseableHttpClient;
 
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 
 /**
  * .
@@ -21,7 +21,7 @@
  * created on  2017/5/4
  */
 public class ApacheSimplePostRequestExecutor extends SimplePostRequestExecutor<CloseableHttpClient, HttpHost> {
-  public ApacheSimplePostRequestExecutor(RequestHttp requestHttp) {
+  public ApacheSimplePostRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
     super(requestHttp);
   }
 
@@ -34,17 +34,12 @@ public String execute(String uri, String postEntity, WxType wxType) throws WxErr
     }
 
     if (postEntity != null) {
-      StringEntity entity = new StringEntity(postEntity, Consts.UTF_8);
-      entity.setContentType("application/json; charset=utf-8");
+      StringEntity entity = new StringEntity(postEntity, ContentType.APPLICATION_JSON.withCharset(StandardCharsets.UTF_8));
       httpPost.setEntity(entity);
     }
 
-    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
-      String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
-      return this.handleResponse(wxType, responseContent);
-    } finally {
-      httpPost.releaseConnection();
-    }
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    return this.handleResponse(wxType, responseContent);
   }
 
 }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ByteArrayResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ByteArrayResponseHandler.java
new file mode 100644
index 0000000000..776b7e32f1
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ByteArrayResponseHandler.java
@@ -0,0 +1,17 @@
+package me.chanjar.weixin.common.util.http.apache;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.impl.client.AbstractResponseHandler;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+
+public class ByteArrayResponseHandler extends AbstractResponseHandler<byte[]> {
+
+  public static final ByteArrayResponseHandler INSTANCE = new ByteArrayResponseHandler();
+
+  @Override
+  public byte[] handleEntity(HttpEntity entity) throws IOException {
+    return EntityUtils.toByteArray(entity);
+  }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java
index 4c06f5168e..ef7120b768 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java
@@ -25,17 +25,13 @@
 import org.apache.http.impl.client.HttpClientBuilder;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
-import org.apache.http.protocol.HttpContext;
 import org.apache.http.ssl.SSLContexts;
 
 import javax.annotation.concurrent.NotThreadSafe;
 import javax.net.ssl.SSLContext;
-import java.io.IOException;
 import java.security.KeyManagementException;
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
@@ -59,7 +55,7 @@ public class DefaultApacheHttpClientBuilder implements ApacheHttpClientBuilder {
    * 设置为负数是使用系统默认设置(非3000ms的默认值,而是httpClient的默认设置).
    * </p>
    */
-  private int connectionRequestTimeout = -1;
+  private int connectionRequestTimeout = 3000;
 
   /**
    * 建立链接的超时时间,默认为5000ms.由于是在链接池获取链接,此设置应该并不起什么作用
@@ -97,6 +93,12 @@ public class DefaultApacheHttpClientBuilder implements ApacheHttpClientBuilder {
    */
   private String userAgent;
 
+  /**
+   * 支持的TLS协议版本，默认支持现代TLS版本
+   * Supported TLS protocol versions, defaults to modern TLS versions
+   */
+  private String[] supportedProtocols = {"TLSv1.2", "TLSv1.3", "TLSv1.1", "TLSv1"};
+
   /**
    * 自定义请求拦截器
    */
@@ -183,6 +185,12 @@ public ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFac
     return this;
   }
 
+  @Override
+  public ApacheHttpClientBuilder supportedProtocols(String[] supportedProtocols) {
+    this.supportedProtocols = supportedProtocols;
+    return this;
+  }
+
   public IdleConnectionMonitorThread getIdleConnectionMonitorThread() {
     return this.idleConnectionMonitorThread;
   }
@@ -261,7 +269,7 @@ private SSLConnectionSocketFactory buildSSLConnectionSocketFactory() {
 
       return new SSLConnectionSocketFactory(
         sslcontext,
-        new String[]{"TLSv1"},
+        this.supportedProtocols,
         null,
         SSLConnectionSocketFactory.getDefaultHostnameVerifier());
     } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/InputStreamResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/InputStreamResponseHandler.java
index 5c72744cb0..1568362611 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/InputStreamResponseHandler.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/InputStreamResponseHandler.java
@@ -1,33 +1,23 @@
 package me.chanjar.weixin.common.util.http.apache;
 
-import java.io.IOException;
-import java.io.InputStream;
-
 import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.StatusLine;
-import org.apache.http.client.HttpResponseException;
 import org.apache.http.client.ResponseHandler;
-import org.apache.http.util.EntityUtils;
+import org.apache.http.impl.client.AbstractResponseHandler;
+
+import java.io.IOException;
+import java.io.InputStream;
 
 /**
  * 输入流响应处理器.
  *
- * @author Daniel Qian
+ * @author altusea
  */
-public class InputStreamResponseHandler implements ResponseHandler<InputStream> {
+public class InputStreamResponseHandler extends AbstractResponseHandler<InputStream> {
+
   public static final ResponseHandler<InputStream> INSTANCE = new InputStreamResponseHandler();
-  private static final int STATUS_CODE_300 = 300;
 
   @Override
-  public InputStream handleResponse(final HttpResponse response) throws IOException {
-    final StatusLine statusLine = response.getStatusLine();
-    final HttpEntity entity = response.getEntity();
-    if (statusLine.getStatusCode() >= STATUS_CODE_300) {
-      EntityUtils.consume(entity);
-      throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
-    }
-    return entity == null ? null : entity.getContent();
+  public InputStream handleEntity(HttpEntity entity) throws IOException {
+    return entity.getContent();
   }
-
 }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/Utf8ResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/Utf8ResponseHandler.java
index 035726d44f..40d96e3ca1 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/Utf8ResponseHandler.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/Utf8ResponseHandler.java
@@ -1,33 +1,24 @@
 package me.chanjar.weixin.common.util.http.apache;
 
-import org.apache.http.Consts;
 import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.StatusLine;
-import org.apache.http.client.HttpResponseException;
 import org.apache.http.client.ResponseHandler;
+import org.apache.http.impl.client.AbstractResponseHandler;
 import org.apache.http.util.EntityUtils;
 
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 
 /**
- * copy from {@link org.apache.http.impl.client.BasicResponseHandler}
+ * Utf8ResponseHandler
  *
- * @author Daniel Qian
+ * @author altusea
  */
-public class Utf8ResponseHandler implements ResponseHandler<String> {
+public class Utf8ResponseHandler extends AbstractResponseHandler<String> {
 
   public static final ResponseHandler<String> INSTANCE = new Utf8ResponseHandler();
 
   @Override
-  public String handleResponse(final HttpResponse response) throws IOException {
-    final StatusLine statusLine = response.getStatusLine();
-    final HttpEntity entity = response.getEntity();
-    if (statusLine.getStatusCode() >= 300) {
-      EntityUtils.consume(entity);
-      throw new HttpResponseException(statusLine.getStatusCode(), statusLine.toString());
-    }
-    return entity == null ? null : EntityUtils.toString(entity, Consts.UTF_8);
+  public String handleEntity(HttpEntity entity) throws IOException {
+    return EntityUtils.toString(entity, StandardCharsets.UTF_8);
   }
-
 }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/BasicResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/BasicResponseHandler.java
new file mode 100644
index 0000000000..f69e14a240
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/BasicResponseHandler.java
@@ -0,0 +1,14 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import org.apache.hc.client5.http.impl.classic.BasicHttpClientResponseHandler;
+
+/**
+ * ApacheBasicResponseHandler
+ *
+ * @author altusea
+ */
+public class BasicResponseHandler extends BasicHttpClientResponseHandler {
+
+  public static final BasicHttpClientResponseHandler INSTANCE = new BasicHttpClientResponseHandler();
+
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/ByteArrayResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/ByteArrayResponseHandler.java
new file mode 100644
index 0000000000..e4a314f866
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/ByteArrayResponseHandler.java
@@ -0,0 +1,22 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import org.apache.hc.client5.http.impl.classic.AbstractHttpClientResponseHandler;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.io.entity.EntityUtils;
+
+import java.io.IOException;
+
+/**
+ * ByteArrayResponseHandler
+ *
+ * @author altusea
+ */
+public class ByteArrayResponseHandler extends AbstractHttpClientResponseHandler<byte[]> {
+
+  public static final ByteArrayResponseHandler INSTANCE = new ByteArrayResponseHandler();
+
+  @Override
+  public byte[] handleEntity(HttpEntity entity) throws IOException {
+    return EntityUtils.toByteArray(entity);
+  }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/DefaultHttpComponentsClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/DefaultHttpComponentsClientBuilder.java
new file mode 100644
index 0000000000..4915e31a16
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/DefaultHttpComponentsClientBuilder.java
@@ -0,0 +1,249 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
+import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
+import org.apache.hc.client5.http.HttpRequestRetryStrategy;
+import org.apache.hc.client5.http.auth.AuthScope;
+import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
+import org.apache.hc.client5.http.config.ConnectionConfig;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
+import org.apache.hc.client5.http.impl.classic.HttpClients;
+import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
+import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
+import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
+import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
+import org.apache.hc.client5.http.ssl.TrustAllStrategy;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.HttpRequestInterceptor;
+import org.apache.hc.core5.http.HttpResponseInterceptor;
+import org.apache.hc.core5.http.io.SocketConfig;
+import org.apache.hc.core5.ssl.SSLContexts;
+
+import javax.annotation.concurrent.NotThreadSafe;
+import javax.net.ssl.SSLContext;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * DefaultApacheHttpClientBuilder
+ *
+ * @author altusea
+ */
+@Slf4j
+@Data
+@NotThreadSafe
+public class DefaultHttpComponentsClientBuilder implements HttpComponentsClientBuilder {
+
+  private final AtomicBoolean prepared = new AtomicBoolean(false);
+
+  /**
+   * 获取链接的超时时间设置
+   * <p>
+   * 设置为零时不超时,一直等待.
+   * 设置为负数是使用系统默认设置(非3000ms的默认值,而是httpClient的默认设置).
+   * </p>
+   */
+  private int connectionRequestTimeout = 3000;
+
+  /**
+   * 建立链接的超时时间,默认为5000ms.由于是在链接池获取链接,此设置应该并不起什么作用
+   * <p>
+   * 设置为零时不超时,一直等待.
+   * 设置为负数是使用系统默认设置(非上述的5000ms的默认值,而是httpclient的默认设置).
+   * </p>
+   */
+  private int connectionTimeout = 5000;
+  /**
+   * 默认NIO的socket超时设置,默认5000ms.
+   */
+  private int soTimeout = 5000;
+  /**
+   * 空闲链接的超时时间,默认60000ms.
+   * <p>
+   * 超时的链接将在下一次空闲链接检查是被销毁
+   * </p>
+   */
+  private int idleConnTimeout = 60000;
+  /**
+   * 检查空间链接的间隔周期,默认60000ms.
+   */
+  private int checkWaitTime = 60000;
+  /**
+   * 每路的最大链接数,默认10
+   */
+  private int maxConnPerHost = 10;
+  /**
+   * 最大总连接数,默认50
+   */
+  private int maxTotalConn = 50;
+  /**
+   * 自定义httpclient的User Agent
+   */
+  private String userAgent;
+
+  /**
+   * 自定义请求拦截器
+   */
+  private List<HttpRequestInterceptor> requestInterceptors = new ArrayList<>();
+
+  /**
+   * 自定义响应拦截器
+   */
+  private List<HttpResponseInterceptor> responseInterceptors = new ArrayList<>();
+
+  /**
+   * 自定义重试策略
+   */
+  private HttpRequestRetryStrategy httpRequestRetryStrategy;
+
+  /**
+   * 自定义KeepAlive策略
+   */
+  private ConnectionKeepAliveStrategy connectionKeepAliveStrategy;
+
+  private String httpProxyHost;
+  private int httpProxyPort;
+  private String httpProxyUsername;
+  private char[] httpProxyPassword;
+  /**
+   * 持有client对象,仅初始化一次,避免多service实例的时候造成重复初始化的问题
+   */
+  private CloseableHttpClient closeableHttpClient;
+
+  private DefaultHttpComponentsClientBuilder() {
+  }
+
+  public static DefaultHttpComponentsClientBuilder get() {
+    return SingletonHolder.INSTANCE;
+  }
+
+  @Override
+  public HttpComponentsClientBuilder httpProxyHost(String httpProxyHost) {
+    this.httpProxyHost = httpProxyHost;
+    return this;
+  }
+
+  @Override
+  public HttpComponentsClientBuilder httpProxyPort(int httpProxyPort) {
+    this.httpProxyPort = httpProxyPort;
+    return this;
+  }
+
+  @Override
+  public HttpComponentsClientBuilder httpProxyUsername(String httpProxyUsername) {
+    this.httpProxyUsername = httpProxyUsername;
+    return this;
+  }
+
+  @Override
+  public HttpComponentsClientBuilder httpProxyPassword(char[] httpProxyPassword) {
+    this.httpProxyPassword = httpProxyPassword;
+    return this;
+  }
+
+  @Override
+  public HttpComponentsClientBuilder httpRequestRetryStrategy(HttpRequestRetryStrategy httpRequestRetryStrategy) {
+    this.httpRequestRetryStrategy = httpRequestRetryStrategy;
+    return this;
+  }
+
+  @Override
+  public HttpComponentsClientBuilder keepAliveStrategy(ConnectionKeepAliveStrategy keepAliveStrategy) {
+    this.connectionKeepAliveStrategy = keepAliveStrategy;
+    return this;
+  }
+
+  private synchronized void prepare() {
+    if (prepared.get()) {
+      return;
+    }
+
+    SSLContext sslcontext;
+    try {
+      sslcontext = SSLContexts.custom()
+        .loadTrustMaterial(TrustAllStrategy.INSTANCE) // 忽略对服务器端证书的校验
+        .build();
+    } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
+      log.error("构建 SSLContext 时发生异常！", e);
+      throw new RuntimeException(e);
+    }
+
+    PoolingHttpClientConnectionManager connManager = PoolingHttpClientConnectionManagerBuilder.create()
+      .setTlsSocketStrategy(new DefaultClientTlsStrategy(sslcontext, NoopHostnameVerifier.INSTANCE))
+      .setMaxConnTotal(this.maxTotalConn)
+      .setMaxConnPerRoute(this.maxConnPerHost)
+      .setDefaultSocketConfig(SocketConfig.custom()
+        .setSoTimeout(this.soTimeout, TimeUnit.MILLISECONDS)
+        .build())
+      .setDefaultConnectionConfig(ConnectionConfig.custom()
+        .setConnectTimeout(this.connectionTimeout, TimeUnit.MILLISECONDS)
+        .build())
+      .build();
+
+    HttpClientBuilder httpClientBuilder = HttpClients.custom()
+      .setConnectionManager(connManager)
+      .setConnectionManagerShared(true)
+      .setDefaultRequestConfig(RequestConfig.custom()
+        .setConnectionRequestTimeout(this.connectionRequestTimeout, TimeUnit.MILLISECONDS)
+        .build()
+      );
+
+    // 设置重试策略，没有则使用默认
+    httpClientBuilder.setRetryStrategy(ObjectUtils.defaultIfNull(httpRequestRetryStrategy, NoopRetryStrategy.INSTANCE));
+
+    // 设置KeepAliveStrategy，没有使用默认
+    if (connectionKeepAliveStrategy != null) {
+      httpClientBuilder.setKeepAliveStrategy(connectionKeepAliveStrategy);
+    }
+
+    if (StringUtils.isNotBlank(this.httpProxyHost) && StringUtils.isNotBlank(this.httpProxyUsername)) {
+      // 使用代理服务器 需要用户认证的代理服务器
+      BasicCredentialsProvider provider = new BasicCredentialsProvider();
+      provider.setCredentials(new AuthScope(this.httpProxyHost, this.httpProxyPort),
+        new UsernamePasswordCredentials(this.httpProxyUsername, this.httpProxyPassword));
+      httpClientBuilder.setDefaultCredentialsProvider(provider);
+      httpClientBuilder.setProxy(new HttpHost(this.httpProxyHost, this.httpProxyPort));
+    }
+
+    if (StringUtils.isNotBlank(this.userAgent)) {
+      httpClientBuilder.setUserAgent(this.userAgent);
+    }
+
+    //添加自定义的请求拦截器
+    requestInterceptors.forEach(httpClientBuilder::addRequestInterceptorFirst);
+
+    //添加自定义的响应拦截器
+    responseInterceptors.forEach(httpClientBuilder::addResponseInterceptorLast);
+
+    this.closeableHttpClient = httpClientBuilder.build();
+    prepared.set(true);
+  }
+
+  @Override
+  public CloseableHttpClient build() {
+    if (!prepared.get()) {
+      prepare();
+    }
+    return this.closeableHttpClient;
+  }
+
+  /**
+   * DefaultApacheHttpClientBuilder 改为单例模式,并持有唯一的CloseableHttpClient(仅首次调用创建)
+   */
+  private static class SingletonHolder {
+    private static final DefaultHttpComponentsClientBuilder INSTANCE = new DefaultHttpComponentsClientBuilder();
+  }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsClientBuilder.java
new file mode 100644
index 0000000000..66cd58e15f
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsClientBuilder.java
@@ -0,0 +1,51 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
+import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
+import org.apache.hc.client5.http.HttpRequestRetryStrategy;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+
+/**
+ * httpclient build interface.
+ *
+ * @author altusea
+ */
+public interface HttpComponentsClientBuilder {
+
+  /**
+   * 构建httpclient实例.
+   *
+   * @return new instance of CloseableHttpClient
+   */
+  CloseableHttpClient build();
+
+  /**
+   * 代理服务器地址.
+   */
+  HttpComponentsClientBuilder httpProxyHost(String httpProxyHost);
+
+  /**
+   * 代理服务器端口.
+   */
+  HttpComponentsClientBuilder httpProxyPort(int httpProxyPort);
+
+  /**
+   * 代理服务器用户名.
+   */
+  HttpComponentsClientBuilder httpProxyUsername(String httpProxyUsername);
+
+  /**
+   * 代理服务器密码.
+   */
+  HttpComponentsClientBuilder httpProxyPassword(char[] httpProxyPassword);
+
+  /**
+   * 重试策略.
+   */
+  HttpComponentsClientBuilder httpRequestRetryStrategy(HttpRequestRetryStrategy httpRequestRetryStrategy);
+
+  /**
+   * 超时时间.
+   */
+  HttpComponentsClientBuilder keepAliveStrategy(ConnectionKeepAliveStrategy keepAliveStrategy);
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMediaDownloadRequestExecutor.java
new file mode 100644
index 0000000000..26fbed93f3
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMediaDownloadRequestExecutor.java
@@ -0,0 +1,79 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.fs.FileUtils;
+import me.chanjar.weixin.common.util.http.BaseMediaDownloadRequestExecutor;
+import me.chanjar.weixin.common.util.http.HttpResponseProxy;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hc.client5.http.ClientProtocolException;
+import org.apache.hc.client5.http.classic.methods.HttpGet;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * ApacheMediaDownloadRequestExecutor
+ *
+ * @author altusea
+ */
+public class HttpComponentsMediaDownloadRequestExecutor extends BaseMediaDownloadRequestExecutor<CloseableHttpClient, HttpHost> {
+
+  public HttpComponentsMediaDownloadRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp, File tmpDirFile) {
+    super(requestHttp, tmpDirFile);
+  }
+
+  @Override
+  public File execute(String uri, String queryParam, WxType wxType) throws WxErrorException, IOException {
+    if (queryParam != null) {
+      if (uri.indexOf('?') == -1) {
+        uri += '?';
+      }
+      uri += uri.endsWith("?") ? queryParam : '&' + queryParam;
+    }
+
+    HttpGet httpGet = new HttpGet(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpGet.setConfig(config);
+    }
+
+    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpGet);
+         InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) {
+      Header[] contentTypeHeader = response.getHeaders("Content-Type");
+      if (contentTypeHeader != null && contentTypeHeader.length > 0) {
+        if (contentTypeHeader[0].getValue().startsWith(ContentType.APPLICATION_JSON.getMimeType())) {
+          // application/json; encoding=utf-8 下载媒体文件出错
+          String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
+          throw new WxErrorException(WxError.fromJson(responseContent, wxType));
+        }
+      }
+
+      String fileName = HttpResponseProxy.from(response).getFileName();
+      if (StringUtils.isBlank(fileName)) {
+        fileName = String.valueOf(System.currentTimeMillis());
+      }
+
+      String baseName = FilenameUtils.getBaseName(fileName);
+      if (StringUtils.isBlank(fileName) || baseName.length() < 3) {
+        baseName = String.valueOf(System.currentTimeMillis());
+      }
+
+      return FileUtils.createTmpFile(inputStream, baseName, FilenameUtils.getExtension(fileName), super.tmpDirFile);
+    } catch (HttpException httpException) {
+      throw new ClientProtocolException(httpException.getMessage(), httpException);
+    }
+  }
+
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMediaInputStreamUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMediaInputStreamUploadRequestExecutor.java
new file mode 100644
index 0000000000..4853b1572b
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMediaInputStreamUploadRequestExecutor.java
@@ -0,0 +1,54 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.InputStreamData;
+import me.chanjar.weixin.common.util.http.MediaInputStreamUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
+import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.IOException;
+
+/**
+ * 文件输入流上传.
+ *
+ * @author altusea
+ */
+public class HttpComponentsMediaInputStreamUploadRequestExecutor extends MediaInputStreamUploadRequestExecutor<CloseableHttpClient, HttpHost> {
+
+  public HttpComponentsMediaInputStreamUploadRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
+
+  @Override
+  public WxMediaUploadResult execute(String uri, InputStreamData data, WxType wxType) throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+    if (data != null) {
+      HttpEntity entity = MultipartEntityBuilder
+        .create()
+        .addBinaryBody("media", data.getInputStream(), ContentType.DEFAULT_BINARY, data.getFilename())
+        .setMode(HttpMultipartMode.EXTENDED)
+        .build();
+      httpPost.setEntity(entity);
+    }
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, wxType);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
+    }
+    return WxMediaUploadResult.fromJson(responseContent);
+  }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMediaUploadRequestExecutor.java
new file mode 100644
index 0000000000..e65d855d52
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMediaUploadRequestExecutor.java
@@ -0,0 +1,53 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
+import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * ApacheMediaUploadRequestExecutor
+ *
+ * @author altusea
+ */
+public class HttpComponentsMediaUploadRequestExecutor extends MediaUploadRequestExecutor<CloseableHttpClient, HttpHost> {
+
+  public HttpComponentsMediaUploadRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
+
+  @Override
+  public WxMediaUploadResult execute(String uri, File file, WxType wxType) throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+    if (file != null) {
+      HttpEntity entity = MultipartEntityBuilder
+        .create()
+        .addBinaryBody("media", file)
+        .setMode(HttpMultipartMode.EXTENDED)
+        .build();
+      httpPost.setEntity(entity);
+    }
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, wxType);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
+    }
+    return WxMediaUploadResult.fromJson(responseContent);
+  }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMinishopMediaUploadRequestCustomizeExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMinishopMediaUploadRequestCustomizeExecutor.java
new file mode 100644
index 0000000000..711f538309
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMinishopMediaUploadRequestCustomizeExecutor.java
@@ -0,0 +1,71 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.bean.result.WxMinishopImageUploadCustomizeResult;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.MinishopUploadRequestCustomizeExecutor;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
+import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * ApacheMinishopMediaUploadRequestCustomizeExecutor
+ *
+ * @author altusea
+ */
+@Slf4j
+public class HttpComponentsMinishopMediaUploadRequestCustomizeExecutor extends MinishopUploadRequestCustomizeExecutor<CloseableHttpClient, HttpHost> {
+
+  public HttpComponentsMinishopMediaUploadRequestCustomizeExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp, String respType, String imgUrl) {
+    super(requestHttp, respType, imgUrl);
+  }
+
+  @Override
+  public WxMinishopImageUploadCustomizeResult execute(String uri, File file, WxType wxType) throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+    if (this.uploadType.equals("0")) {
+      if (file == null) {
+        throw new WxErrorException("上传文件为空");
+      }
+      HttpEntity entity = MultipartEntityBuilder
+        .create()
+        .addBinaryBody("media", file)
+        .addTextBody("resp_type", this.respType)
+        .addTextBody("upload_type", this.uploadType)
+        .setMode(HttpMultipartMode.EXTENDED)
+        .build();
+      httpPost.setEntity(entity);
+    }
+    else {
+      HttpEntity entity = MultipartEntityBuilder
+              .create()
+              .addTextBody("resp_type", this.respType)
+              .addTextBody("upload_type", this.uploadType)
+              .addTextBody("img_url", this.imgUrl)
+              .setMode(org.apache.hc.client5.http.entity.mime.HttpMultipartMode.EXTENDED)
+              .build();
+      httpPost.setEntity(entity);
+    }
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, wxType);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
+    }
+    log.info("responseContent: {}", responseContent);
+    return WxMinishopImageUploadCustomizeResult.fromJson(responseContent);
+  }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMinishopMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMinishopMediaUploadRequestExecutor.java
new file mode 100644
index 0000000000..72c1f2765f
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsMinishopMediaUploadRequestExecutor.java
@@ -0,0 +1,56 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.bean.result.WxMinishopImageUploadResult;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.MinishopUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
+import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * ApacheMinishopMediaUploadRequestExecutor
+ *
+ * @author altusea
+ */
+@Slf4j
+public class HttpComponentsMinishopMediaUploadRequestExecutor extends MinishopUploadRequestExecutor<CloseableHttpClient, HttpHost> {
+
+  public HttpComponentsMinishopMediaUploadRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
+
+  @Override
+  public WxMinishopImageUploadResult execute(String uri, File file, WxType wxType) throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+    if (file != null) {
+      HttpEntity entity = MultipartEntityBuilder
+        .create()
+        .addBinaryBody("media", file)
+        .setMode(HttpMultipartMode.EXTENDED)
+        .build();
+      httpPost.setEntity(entity);
+    }
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, wxType);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
+    }
+    log.info("responseContent: {}", responseContent);
+    return WxMinishopImageUploadResult.fromJson(responseContent);
+  }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsResponseProxy.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsResponseProxy.java
new file mode 100644
index 0000000000..d55ff0735f
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsResponseProxy.java
@@ -0,0 +1,25 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.HttpResponseProxy;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
+import org.apache.hc.core5.http.Header;
+
+public class HttpComponentsResponseProxy implements HttpResponseProxy {
+
+  private final CloseableHttpResponse response;
+
+  public HttpComponentsResponseProxy(CloseableHttpResponse closeableHttpResponse) {
+    this.response = closeableHttpResponse;
+  }
+
+  @Override
+  public String getFileName() throws WxErrorException {
+    Header[] contentDispositionHeader = this.response.getHeaders("Content-disposition");
+    if (contentDispositionHeader == null || contentDispositionHeader.length == 0) {
+      throw new WxErrorException("无法获取到文件名，Content-disposition为空");
+    }
+
+    return HttpResponseProxy.extractFileNameFromContentString(contentDispositionHeader[0].getValue());
+  }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsSimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsSimpleGetRequestExecutor.java
new file mode 100644
index 0000000000..0d212fe7e2
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsSimpleGetRequestExecutor.java
@@ -0,0 +1,43 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
+import org.apache.hc.client5.http.classic.methods.HttpGet;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.IOException;
+
+/**
+ * ApacheSimpleGetRequestExecutor
+ *
+ * @author altusea
+ */
+public class HttpComponentsSimpleGetRequestExecutor extends SimpleGetRequestExecutor<CloseableHttpClient, HttpHost> {
+
+  public HttpComponentsSimpleGetRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
+
+  @Override
+  public String execute(String uri, String queryParam, WxType wxType) throws WxErrorException, IOException {
+    if (queryParam != null) {
+      if (uri.indexOf('?') == -1) {
+        uri += '?';
+      }
+      uri += uri.endsWith("?") ? queryParam : '&' + queryParam;
+    }
+    HttpGet httpGet = new HttpGet(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpGet.setConfig(config);
+    }
+
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpGet, Utf8ResponseHandler.INSTANCE);
+    return handleResponse(wxType, responseContent);
+  }
+
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsSimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsSimplePostRequestExecutor.java
new file mode 100644
index 0000000000..45d2ca9f6e
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/HttpComponentsSimplePostRequestExecutor.java
@@ -0,0 +1,45 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * ApacheSimplePostRequestExecutor
+ *
+ * @author altusea
+ */
+public class HttpComponentsSimplePostRequestExecutor extends SimplePostRequestExecutor<CloseableHttpClient, HttpHost> {
+
+  public HttpComponentsSimplePostRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
+
+  @Override
+  public String execute(String uri, String postEntity, WxType wxType) throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+
+    if (postEntity != null) {
+      StringEntity entity = new StringEntity(postEntity, ContentType.APPLICATION_JSON.withCharset(StandardCharsets.UTF_8));
+      httpPost.setEntity(entity);
+    }
+
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    return this.handleResponse(wxType, responseContent);
+  }
+
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/InputStreamResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/InputStreamResponseHandler.java
new file mode 100644
index 0000000000..27308151f7
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/InputStreamResponseHandler.java
@@ -0,0 +1,23 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import org.apache.hc.client5.http.impl.classic.AbstractHttpClientResponseHandler;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.io.HttpClientResponseHandler;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * InputStreamResponseHandler
+ *
+ * @author altusea
+ */
+public class InputStreamResponseHandler extends AbstractHttpClientResponseHandler<InputStream> {
+
+  public static final HttpClientResponseHandler<InputStream> INSTANCE = new InputStreamResponseHandler();
+
+  @Override
+  public InputStream handleEntity(HttpEntity entity) throws IOException {
+    return entity.getContent();
+  }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/NoopRetryStrategy.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/NoopRetryStrategy.java
new file mode 100644
index 0000000000..9b4e3bc384
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/NoopRetryStrategy.java
@@ -0,0 +1,34 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import org.apache.hc.client5.http.HttpRequestRetryStrategy;
+import org.apache.hc.core5.http.HttpRequest;
+import org.apache.hc.core5.http.HttpResponse;
+import org.apache.hc.core5.http.protocol.HttpContext;
+import org.apache.hc.core5.util.TimeValue;
+
+import java.io.IOException;
+
+/**
+ * NoopRetryStrategy
+ *
+ * @author altusea
+ */
+public class NoopRetryStrategy implements HttpRequestRetryStrategy {
+
+  public static final HttpRequestRetryStrategy INSTANCE = new NoopRetryStrategy();
+
+  @Override
+  public boolean retryRequest(HttpRequest request, IOException exception, int execCount, HttpContext context) {
+    return false;
+  }
+
+  @Override
+  public boolean retryRequest(HttpResponse response, int execCount, HttpContext context) {
+    return false;
+  }
+
+  @Override
+  public TimeValue getRetryInterval(HttpResponse response, int execCount, HttpContext context) {
+    return TimeValue.ZERO_MILLISECONDS;
+  }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/Utf8ResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/Utf8ResponseHandler.java
new file mode 100644
index 0000000000..81699ef57b
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/hc/Utf8ResponseHandler.java
@@ -0,0 +1,30 @@
+package me.chanjar.weixin.common.util.http.hc;
+
+import org.apache.hc.client5.http.ClientProtocolException;
+import org.apache.hc.client5.http.impl.classic.AbstractHttpClientResponseHandler;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.ParseException;
+import org.apache.hc.core5.http.io.HttpClientResponseHandler;
+import org.apache.hc.core5.http.io.entity.EntityUtils;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Utf8ResponseHandler
+ *
+ * @author altusea
+ */
+public class Utf8ResponseHandler extends AbstractHttpClientResponseHandler<String> {
+
+  public static final HttpClientResponseHandler<String> INSTANCE = new Utf8ResponseHandler();
+
+  @Override
+  public String handleEntity(HttpEntity entity) throws IOException {
+    try {
+      return EntityUtils.toString(entity, StandardCharsets.UTF_8);
+    } catch (final ParseException ex) {
+      throw new ClientProtocolException(ex);
+    }
+  }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaDownloadRequestExecutor.java
index 920cf2d03b..bc2fbc17f3 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaDownloadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaDownloadRequestExecutor.java
@@ -4,7 +4,6 @@
 import jodd.http.HttpRequest;
 import jodd.http.HttpResponse;
 import jodd.http.ProxyInfo;
-import jodd.util.StringPool;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
@@ -28,7 +27,7 @@
  * created on  2017/5/5
  */
 public class JoddHttpMediaDownloadRequestExecutor extends BaseMediaDownloadRequestExecutor<HttpConnectionProvider, ProxyInfo> {
-  public JoddHttpMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) {
+  public JoddHttpMediaDownloadRequestExecutor(RequestHttp<HttpConnectionProvider, ProxyInfo> requestHttp, File tmpDirFile) {
     super(requestHttp, tmpDirFile);
   }
 
@@ -56,7 +55,7 @@ public File execute(String uri, String queryParam, WxType wxType) throws WxError
       throw new WxErrorException(WxError.fromJson(response.bodyText(), wxType));
     }
 
-    String fileName = new HttpResponseProxy(response).getFileName();
+    String fileName = HttpResponseProxy.from(response).getFileName();
     if (StringUtils.isBlank(fileName)) {
       return null;
     }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaInputStreamUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaInputStreamUploadRequestExecutor.java
index 311b7c49c5..915db21c65 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaInputStreamUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaInputStreamUploadRequestExecutor.java
@@ -25,7 +25,7 @@
  * created on  2022/02/15
  */
 public class JoddHttpMediaInputStreamUploadRequestExecutor extends MediaInputStreamUploadRequestExecutor<HttpConnectionProvider, ProxyInfo> {
-  public JoddHttpMediaInputStreamUploadRequestExecutor(RequestHttp requestHttp) {
+  public JoddHttpMediaInputStreamUploadRequestExecutor(RequestHttp<HttpConnectionProvider, ProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaUploadRequestExecutor.java
index 876caa29fb..1ed59a71da 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaUploadRequestExecutor.java
@@ -4,7 +4,6 @@
 import jodd.http.HttpRequest;
 import jodd.http.HttpResponse;
 import jodd.http.ProxyInfo;
-import jodd.util.StringPool;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
 import me.chanjar.weixin.common.error.WxError;
@@ -23,7 +22,7 @@
  * created on  2017/5/5
  */
 public class JoddHttpMediaUploadRequestExecutor extends MediaUploadRequestExecutor<HttpConnectionProvider, ProxyInfo> {
-  public JoddHttpMediaUploadRequestExecutor(RequestHttp requestHttp) {
+  public JoddHttpMediaUploadRequestExecutor(RequestHttp<HttpConnectionProvider, ProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMinishopMediaUploadRequestCustomizeExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMinishopMediaUploadRequestCustomizeExecutor.java
index 1d6f24fa2a..66074d8103 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMinishopMediaUploadRequestCustomizeExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMinishopMediaUploadRequestCustomizeExecutor.java
@@ -22,7 +22,7 @@
  */
 @Slf4j
 public class JoddHttpMinishopMediaUploadRequestCustomizeExecutor extends MinishopUploadRequestCustomizeExecutor<HttpConnectionProvider, ProxyInfo> {
-  public JoddHttpMinishopMediaUploadRequestCustomizeExecutor(RequestHttp requestHttp, String respType, String imgUrl) {
+  public JoddHttpMinishopMediaUploadRequestCustomizeExecutor(RequestHttp<HttpConnectionProvider, ProxyInfo> requestHttp, String respType, String imgUrl) {
     super(requestHttp, respType, imgUrl);
   }
 
@@ -51,7 +51,7 @@ public WxMinishopImageUploadCustomizeResult execute(String uri, File file, WxTyp
     if (error.getErrorCode() != 0) {
       throw new WxErrorException(error);
     }
-    log.info("responseContent: " + responseContent);
+    log.info("responseContent: {}", responseContent);
 
     return WxMinishopImageUploadCustomizeResult.fromJson(responseContent);
   }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMinishopMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMinishopMediaUploadRequestExecutor.java
index 4cb9c50ee0..c7c35dd798 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMinishopMediaUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMinishopMediaUploadRequestExecutor.java
@@ -5,12 +5,10 @@
 import jodd.http.HttpResponse;
 import jodd.http.ProxyInfo;
 import lombok.extern.slf4j.Slf4j;
-import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
 import me.chanjar.weixin.common.bean.result.WxMinishopImageUploadResult;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
 import me.chanjar.weixin.common.util.http.MinishopUploadRequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 
@@ -26,7 +24,7 @@
  */
 @Slf4j
 public class JoddHttpMinishopMediaUploadRequestExecutor extends MinishopUploadRequestExecutor<HttpConnectionProvider, ProxyInfo> {
-  public JoddHttpMinishopMediaUploadRequestExecutor(RequestHttp requestHttp) {
+  public JoddHttpMinishopMediaUploadRequestExecutor(RequestHttp<HttpConnectionProvider, ProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
@@ -46,7 +44,7 @@ public WxMinishopImageUploadResult execute(String uri, File file, WxType wxType)
     if (error.getErrorCode() != 0) {
       throw new WxErrorException(error);
     }
-    log.info("responseContent: " + responseContent);
+    log.info("responseContent: {}", responseContent);
 
     return WxMinishopImageUploadResult.fromJson(responseContent);
   }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpResponseProxy.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpResponseProxy.java
new file mode 100644
index 0000000000..1bda38a497
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpResponseProxy.java
@@ -0,0 +1,20 @@
+package me.chanjar.weixin.common.util.http.jodd;
+
+import jodd.http.HttpResponse;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.HttpResponseProxy;
+
+public class JoddHttpResponseProxy implements HttpResponseProxy {
+
+  private final HttpResponse response;
+
+  public JoddHttpResponseProxy(HttpResponse httpResponse) {
+    this.response = httpResponse;
+  }
+
+  @Override
+  public String getFileName() throws WxErrorException {
+    String content = response.header("Content-disposition");
+    return HttpResponseProxy.extractFileNameFromContentString(content);
+  }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimpleGetRequestExecutor.java
index 869ea8c04e..ed8288b04f 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimpleGetRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimpleGetRequestExecutor.java
@@ -4,7 +4,6 @@
 import jodd.http.HttpRequest;
 import jodd.http.HttpResponse;
 import jodd.http.ProxyInfo;
-import jodd.util.StringPool;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestHttp;
@@ -20,7 +19,7 @@
  * created on  2017/5/4
  */
 public class JoddHttpSimpleGetRequestExecutor extends SimpleGetRequestExecutor<HttpConnectionProvider, ProxyInfo> {
-  public JoddHttpSimpleGetRequestExecutor(RequestHttp requestHttp) {
+  public JoddHttpSimpleGetRequestExecutor(RequestHttp<HttpConnectionProvider, ProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimplePostRequestExecutor.java
index 654378271c..095493c75e 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimplePostRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpSimplePostRequestExecutor.java
@@ -19,7 +19,7 @@
  * created on  2017/5/4
  */
 public class JoddHttpSimplePostRequestExecutor extends SimplePostRequestExecutor<HttpConnectionProvider, ProxyInfo> {
-  public JoddHttpSimplePostRequestExecutor(RequestHttp requestHttp) {
+  public JoddHttpSimplePostRequestExecutor(RequestHttp<HttpConnectionProvider, ProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java
index dda52e2f7b..0610d3f51c 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaDownloadRequestExecutor.java
@@ -25,7 +25,7 @@
  */
 @Slf4j
 public class OkHttpMediaDownloadRequestExecutor extends BaseMediaDownloadRequestExecutor<OkHttpClient, OkHttpProxyInfo> {
-  public OkHttpMediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) {
+  public OkHttpMediaDownloadRequestExecutor(RequestHttp<OkHttpClient, OkHttpProxyInfo> requestHttp, File tmpDirFile) {
     super(requestHttp, tmpDirFile);
   }
 
@@ -51,7 +51,7 @@ public File execute(String uri, String queryParam, WxType wxType) throws WxError
       throw new WxErrorException(WxError.fromJson(response.body().string(), wxType));
     }
 
-    String fileName = new HttpResponseProxy(response).getFileName();
+    String fileName = HttpResponseProxy.from(response).getFileName();
     if (StringUtils.isBlank(fileName)) {
       return null;
     }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaInputStreamUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaInputStreamUploadRequestExecutor.java
index 613bd7ecfa..c30cc619aa 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaInputStreamUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaInputStreamUploadRequestExecutor.java
@@ -20,7 +20,7 @@
  * created on  2022/02/15
  */
 public class OkHttpMediaInputStreamUploadRequestExecutor extends MediaInputStreamUploadRequestExecutor<OkHttpClient, OkHttpProxyInfo> {
-  public OkHttpMediaInputStreamUploadRequestExecutor(RequestHttp requestHttp) {
+  public OkHttpMediaInputStreamUploadRequestExecutor(RequestHttp<OkHttpClient, OkHttpProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java
index 1b5241ff70..6a7b0b794d 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaUploadRequestExecutor.java
@@ -18,7 +18,7 @@
  * created on  2017/5/5
  */
 public class OkHttpMediaUploadRequestExecutor extends MediaUploadRequestExecutor<OkHttpClient, OkHttpProxyInfo> {
-  public OkHttpMediaUploadRequestExecutor(RequestHttp requestHttp) {
+  public OkHttpMediaUploadRequestExecutor(RequestHttp<OkHttpClient, OkHttpProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMinishopMediaUploadRequestCustomizeExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMinishopMediaUploadRequestCustomizeExecutor.java
index a8b76321ca..a2c78f423b 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMinishopMediaUploadRequestCustomizeExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMinishopMediaUploadRequestCustomizeExecutor.java
@@ -18,7 +18,7 @@
  */
 @Slf4j
 public class OkHttpMinishopMediaUploadRequestCustomizeExecutor extends MinishopUploadRequestCustomizeExecutor<OkHttpClient, OkHttpProxyInfo> {
-  public OkHttpMinishopMediaUploadRequestCustomizeExecutor(RequestHttp requestHttp, String respType, String imgUrl) {
+  public OkHttpMinishopMediaUploadRequestCustomizeExecutor(RequestHttp<OkHttpClient, OkHttpProxyInfo> requestHttp, String respType, String imgUrl) {
     super(requestHttp, respType, imgUrl);
   }
 
@@ -50,7 +50,7 @@ public WxMinishopImageUploadCustomizeResult execute(String uri, File file, WxTyp
     if (error.getErrorCode() != 0) {
       throw new WxErrorException(error);
     }
-    log.info("responseContent: " + responseContent);
+    log.info("responseContent: {}", responseContent);
 
     return WxMinishopImageUploadCustomizeResult.fromJson(responseContent);
   }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMinishopMediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMinishopMediaUploadRequestExecutor.java
index 5c40b1f6ba..f2df3c7e73 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMinishopMediaUploadRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMinishopMediaUploadRequestExecutor.java
@@ -1,12 +1,10 @@
 package me.chanjar.weixin.common.util.http.okhttp;
 
 import lombok.extern.slf4j.Slf4j;
-import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
 import me.chanjar.weixin.common.bean.result.WxMinishopImageUploadResult;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
 import me.chanjar.weixin.common.util.http.MinishopUploadRequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import okhttp3.*;
@@ -22,7 +20,7 @@
  */
 @Slf4j
 public class OkHttpMinishopMediaUploadRequestExecutor extends MinishopUploadRequestExecutor<OkHttpClient, OkHttpProxyInfo> {
-  public OkHttpMinishopMediaUploadRequestExecutor(RequestHttp requestHttp) {
+  public OkHttpMinishopMediaUploadRequestExecutor(RequestHttp<OkHttpClient, OkHttpProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
@@ -43,7 +41,7 @@ public WxMinishopImageUploadResult execute(String uri, File file, WxType wxType)
     if (error.getErrorCode() != 0) {
       throw new WxErrorException(error);
     }
-    log.info("responseContent: " + responseContent);
+    log.info("responseContent: {}", responseContent);
 
     return WxMinishopImageUploadResult.fromJson(responseContent);
   }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpResponseProxy.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpResponseProxy.java
new file mode 100644
index 0000000000..95c290735c
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpResponseProxy.java
@@ -0,0 +1,20 @@
+package me.chanjar.weixin.common.util.http.okhttp;
+
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.HttpResponseProxy;
+import okhttp3.Response;
+
+public class OkHttpResponseProxy implements HttpResponseProxy {
+
+  private final Response response;
+
+  public OkHttpResponseProxy(Response response) {
+    this.response = response;
+  }
+
+  @Override
+  public String getFileName() throws WxErrorException {
+    String content = this.response.header("Content-disposition");
+    return HttpResponseProxy.extractFileNameFromContentString(content);
+  }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimpleGetRequestExecutor.java
index 2a41ea0508..d475222872 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimpleGetRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimpleGetRequestExecutor.java
@@ -17,7 +17,7 @@
  * created on  2017/5/4
  */
 public class OkHttpSimpleGetRequestExecutor extends SimpleGetRequestExecutor<OkHttpClient, OkHttpProxyInfo> {
-  public OkHttpSimpleGetRequestExecutor(RequestHttp requestHttp) {
+  public OkHttpSimpleGetRequestExecutor(RequestHttp<OkHttpClient, OkHttpProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimplePostRequestExecutor.java
index a289f362e3..3044f29d60 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimplePostRequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpSimplePostRequestExecutor.java
@@ -18,7 +18,7 @@
  */
 @Slf4j
 public class OkHttpSimplePostRequestExecutor extends SimplePostRequestExecutor<OkHttpClient, OkHttpProxyInfo> {
-  public OkHttpSimplePostRequestExecutor(RequestHttp requestHttp) {
+  public OkHttpSimplePostRequestExecutor(RequestHttp<OkHttpClient, OkHttpProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/GsonParser.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/GsonParser.java
index 061a3cb2ee..f2646436c0 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/GsonParser.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/GsonParser.java
@@ -10,17 +10,16 @@
  * @author niefy
  */
 public class GsonParser {
-  private static final JsonParser JSON_PARSER = new JsonParser();
 
   public static JsonObject parse(String json) {
-    return JSON_PARSER.parse(json).getAsJsonObject();
+    return JsonParser.parseString(json).getAsJsonObject();
   }
 
   public static JsonObject parse(Reader json) {
-    return JSON_PARSER.parse(json).getAsJsonObject();
+    return JsonParser.parseReader(json).getAsJsonObject();
   }
 
   public static JsonObject parse(JsonReader json) {
-    return JSON_PARSER.parse(json).getAsJsonObject();
+    return JsonParser.parseReader(json).getAsJsonObject();
   }
 }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java
index 50d3b0d630..5e7f9b41d9 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxMenuGsonAdapter.java
@@ -1,11 +1,3 @@
-/*
- * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved.
- *
- * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended
- * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction
- * arose from modification of the original source, or other redistribution of this source
- * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD.
- */
 package me.chanjar.weixin.common.util.json;
 
 import com.google.gson.*;
@@ -14,6 +6,7 @@
 import me.chanjar.weixin.common.bean.menu.WxMenuRule;
 
 import java.lang.reflect.Type;
+import java.util.Optional;
 
 
 /**
@@ -21,96 +14,111 @@
  */
 public class WxMenuGsonAdapter implements JsonSerializer<WxMenu>, JsonDeserializer<WxMenu> {
 
+  // JSON字段常量定义
+  private static final String FIELD_BUTTON = "button";
+  private static final String FIELD_MATCH_RULE = "matchrule";
+  private static final String FIELD_SUB_BUTTON = "sub_button";
+  private static final String FIELD_MENU = "menu";
+
+  // 菜单按钮字段常量
+  private static final String FIELD_TYPE = "type";
+  private static final String FIELD_NAME = "name";
+  private static final String FIELD_KEY = "key";
+  private static final String FIELD_URL = "url";
+  private static final String FIELD_MEDIA_ID = "media_id";
+  private static final String FIELD_ARTICLE_ID = "article_id";
+  private static final String FIELD_APP_ID = "appid";
+  private static final String FIELD_PAGE_PATH = "pagepath";
+
+  // 菜单规则字段常量
+  private static final String FIELD_TAG_ID = "tag_id";
+  private static final String FIELD_SEX = "sex";
+  private static final String FIELD_COUNTRY = "country";
+  private static final String FIELD_PROVINCE = "province";
+  private static final String FIELD_CITY = "city";
+  private static final String FIELD_CLIENT_PLATFORM_TYPE = "client_platform_type";
+  private static final String FIELD_LANGUAGE = "language";
+
   @Override
   public JsonElement serialize(WxMenu menu, Type typeOfSrc, JsonSerializationContext context) {
     JsonObject json = new JsonObject();
-
     JsonArray buttonArray = new JsonArray();
-    for (WxMenuButton button : menu.getButtons()) {
-      JsonObject buttonJson = convertToJson(button);
-      buttonArray.add(buttonJson);
-    }
-    json.add("button", buttonArray);
-
+    Optional.ofNullable(menu.getButtons())
+        .ifPresent(buttons -> buttons.stream()
+            .map(this::convertToJson)
+            .forEach(buttonArray::add));
+    json.add(FIELD_BUTTON, buttonArray);
     if (menu.getMatchRule() != null) {
-      json.add("matchrule", convertToJson(menu.getMatchRule()));
+      json.add(FIELD_MATCH_RULE, convertToJson(menu.getMatchRule()));
     }
-
     return json;
   }
 
   protected JsonObject convertToJson(WxMenuButton button) {
     JsonObject buttonJson = new JsonObject();
-    buttonJson.addProperty("type", button.getType());
-    buttonJson.addProperty("name", button.getName());
-    buttonJson.addProperty("key", button.getKey());
-    buttonJson.addProperty("url", button.getUrl());
-    buttonJson.addProperty("media_id", button.getMediaId());
-    buttonJson.addProperty("article_id", button.getArticleId());
-    buttonJson.addProperty("appid", button.getAppId());
-    buttonJson.addProperty("pagepath", button.getPagePath());
-    if (button.getSubButtons() != null && button.getSubButtons().size() > 0) {
+    addPropertyIfNotNull(buttonJson, FIELD_TYPE, button.getType());
+    addPropertyIfNotNull(buttonJson, FIELD_NAME, button.getName());
+    addPropertyIfNotNull(buttonJson, FIELD_KEY, button.getKey());
+    addPropertyIfNotNull(buttonJson, FIELD_URL, button.getUrl());
+    addPropertyIfNotNull(buttonJson, FIELD_MEDIA_ID, button.getMediaId());
+    addPropertyIfNotNull(buttonJson, FIELD_ARTICLE_ID, button.getArticleId());
+    addPropertyIfNotNull(buttonJson, FIELD_APP_ID, button.getAppId());
+    addPropertyIfNotNull(buttonJson, FIELD_PAGE_PATH, button.getPagePath());
+    if (button.getSubButtons() != null && !button.getSubButtons().isEmpty()) {
       JsonArray buttonArray = new JsonArray();
-      for (WxMenuButton sub_button : button.getSubButtons()) {
-        buttonArray.add(convertToJson(sub_button));
-      }
-      buttonJson.add("sub_button", buttonArray);
+      button.getSubButtons().stream()
+          .map(this::convertToJson)
+          .forEach(buttonArray::add);
+      buttonJson.add(FIELD_SUB_BUTTON, buttonArray);
     }
     return buttonJson;
   }
 
   protected JsonObject convertToJson(WxMenuRule menuRule) {
     JsonObject matchRule = new JsonObject();
-    matchRule.addProperty("tag_id", menuRule.getTagId());
-    matchRule.addProperty("sex", menuRule.getSex());
-    matchRule.addProperty("country", menuRule.getCountry());
-    matchRule.addProperty("province", menuRule.getProvince());
-    matchRule.addProperty("city", menuRule.getCity());
-    matchRule.addProperty("client_platform_type", menuRule.getClientPlatformType());
-    matchRule.addProperty("language", menuRule.getLanguage());
+    addPropertyIfNotNull(matchRule, FIELD_TAG_ID, menuRule.getTagId());
+    addPropertyIfNotNull(matchRule, FIELD_SEX, menuRule.getSex());
+    addPropertyIfNotNull(matchRule, FIELD_COUNTRY, menuRule.getCountry());
+    addPropertyIfNotNull(matchRule, FIELD_PROVINCE, menuRule.getProvince());
+    addPropertyIfNotNull(matchRule, FIELD_CITY, menuRule.getCity());
+    addPropertyIfNotNull(matchRule, FIELD_CLIENT_PLATFORM_TYPE, menuRule.getClientPlatformType());
+    addPropertyIfNotNull(matchRule, FIELD_LANGUAGE, menuRule.getLanguage());
     return matchRule;
   }
 
-  @Deprecated
-  private WxMenuRule convertToRule(JsonObject json) {
-    WxMenuRule menuRule = new WxMenuRule();
-    //变态的微信接口，这里居然反人类的使用和序列化时不一样的名字
-    //menuRule.setTagId(GsonHelper.getString(json,"tag_id"));
-    menuRule.setTagId(GsonHelper.getString(json, "group_id"));
-    menuRule.setSex(GsonHelper.getString(json, "sex"));
-    menuRule.setCountry(GsonHelper.getString(json, "country"));
-    menuRule.setProvince(GsonHelper.getString(json, "province"));
-    menuRule.setCity(GsonHelper.getString(json, "city"));
-    menuRule.setClientPlatformType(GsonHelper.getString(json, "client_platform_type"));
-    menuRule.setLanguage(GsonHelper.getString(json, "language"));
-    return menuRule;
+  private void addPropertyIfNotNull(JsonObject obj, String key, String value) {
+    if (value != null) {
+      obj.addProperty(key, value);
+    }
   }
 
   @Override
   public WxMenu deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
-    /*
-     * 操蛋的微信
-     * 创建菜单时是 { button : ... }
-     * 查询菜单时是 { menu : { button : ... } }
-     * 现在企业号升级为企业微信后，没有此问题，因此需要单独处理
-     */
-    JsonArray buttonsJson = json.getAsJsonObject().get("menu").getAsJsonObject().get("button").getAsJsonArray();
-    return this.buildMenuFromJson(buttonsJson);
+    JsonObject root = json.getAsJsonObject();
+    JsonArray buttonsJson = null;
+    if (root.has(FIELD_MENU)) {
+      JsonObject menuObj = root.getAsJsonObject(FIELD_MENU);
+      buttonsJson = menuObj.getAsJsonArray(FIELD_BUTTON);
+    } else if (root.has(FIELD_BUTTON)) {
+      buttonsJson = root.getAsJsonArray(FIELD_BUTTON);
+    }
+    if (buttonsJson == null) {
+      throw new JsonParseException("No button array found in menu JSON");
+    }
+    return buildMenuFromJson(buttonsJson);
   }
 
   protected WxMenu buildMenuFromJson(JsonArray buttonsJson) {
     WxMenu menu = new WxMenu();
-    for (int i = 0; i < buttonsJson.size(); i++) {
-      JsonObject buttonJson = buttonsJson.get(i).getAsJsonObject();
+    for (JsonElement btnElem : buttonsJson) {
+      JsonObject buttonJson = btnElem.getAsJsonObject();
       WxMenuButton button = convertFromJson(buttonJson);
       menu.getButtons().add(button);
-      if (buttonJson.get("sub_button") == null || buttonJson.get("sub_button").isJsonNull()) {
-        continue;
-      }
-      JsonArray sub_buttonsJson = buttonJson.get("sub_button").getAsJsonArray();
-      for (int j = 0; j < sub_buttonsJson.size(); j++) {
-        JsonObject sub_buttonJson = sub_buttonsJson.get(j).getAsJsonObject();
-        button.getSubButtons().add(convertFromJson(sub_buttonJson));
+      if (buttonJson.has(FIELD_SUB_BUTTON) && buttonJson.get(FIELD_SUB_BUTTON).isJsonArray()) {
+        JsonArray sub_buttonsJson = buttonJson.getAsJsonArray(FIELD_SUB_BUTTON);
+        for (JsonElement subBtnElem : sub_buttonsJson) {
+          button.getSubButtons().add(convertFromJson(subBtnElem.getAsJsonObject()));
+        }
       }
     }
     return menu;
@@ -118,14 +126,14 @@ protected WxMenu buildMenuFromJson(JsonArray buttonsJson) {
 
   protected WxMenuButton convertFromJson(JsonObject json) {
     WxMenuButton button = new WxMenuButton();
-    button.setName(GsonHelper.getString(json, "name"));
-    button.setKey(GsonHelper.getString(json, "key"));
-    button.setUrl(GsonHelper.getString(json, "url"));
-    button.setType(GsonHelper.getString(json, "type"));
-    button.setMediaId(GsonHelper.getString(json, "media_id"));
-    button.setArticleId(GsonHelper.getString(json, "article_id"));
-    button.setAppId(GsonHelper.getString(json, "appid"));
-    button.setPagePath(GsonHelper.getString(json, "pagepath"));
+    button.setName(GsonHelper.getString(json, FIELD_NAME));
+    button.setKey(GsonHelper.getString(json, FIELD_KEY));
+    button.setUrl(GsonHelper.getString(json, FIELD_URL));
+    button.setType(GsonHelper.getString(json, FIELD_TYPE));
+    button.setMediaId(GsonHelper.getString(json, FIELD_MEDIA_ID));
+    button.setArticleId(GsonHelper.getString(json, FIELD_ARTICLE_ID));
+    button.setAppId(GsonHelper.getString(json, FIELD_APP_ID));
+    button.setPagePath(GsonHelper.getString(json, FIELD_PAGE_PATH));
     return button;
   }
 
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxNetCheckResultGsonAdapter.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxNetCheckResultGsonAdapter.java
index 65c15fbc38..61492cbc7a 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxNetCheckResultGsonAdapter.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/json/WxNetCheckResultGsonAdapter.java
@@ -20,7 +20,7 @@ public WxNetCheckResult deserialize(JsonElement json, Type typeOfT, JsonDeserial
 
     JsonArray dnssJson = json.getAsJsonObject().get("dns").getAsJsonArray();
     List<WxNetCheckResult.WxNetCheckDnsInfo> dnsInfoList = new ArrayList<>();
-    if (dnssJson != null && dnssJson.size() > 0) {
+    if (dnssJson != null && !dnssJson.isEmpty()) {
       for (int i = 0; i < dnssJson.size(); i++) {
         JsonObject buttonJson = dnssJson.get(i).getAsJsonObject();
         WxNetCheckResult.WxNetCheckDnsInfo dnsInfo = new WxNetCheckResult.WxNetCheckDnsInfo();
@@ -32,7 +32,7 @@ public WxNetCheckResult deserialize(JsonElement json, Type typeOfT, JsonDeserial
 
     JsonArray pingsJson = json.getAsJsonObject().get("ping").getAsJsonArray();
     List<WxNetCheckResult.WxNetCheckPingInfo> pingInfoList = new ArrayList<>();
-    if (pingsJson != null && pingsJson.size() > 0) {
+    if (pingsJson != null && !pingsJson.isEmpty()) {
       for (int i = 0; i < pingsJson.size(); i++) {
         JsonObject pingJson = pingsJson.get(i).getAsJsonObject();
         WxNetCheckResult.WxNetCheckPingInfo pingInfo = new WxNetCheckResult.WxNetCheckPingInfo();
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/locks/RedisTemplateSimpleDistributedLock.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/locks/RedisTemplateSimpleDistributedLock.java
index 214b4547b0..b2d2481efe 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/locks/RedisTemplateSimpleDistributedLock.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/locks/RedisTemplateSimpleDistributedLock.java
@@ -9,7 +9,7 @@
 import org.springframework.data.redis.core.types.Expiration;
 
 import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.UUID;
 import java.util.concurrent.TimeUnit;
@@ -66,7 +66,7 @@ public void lockInterruptibly() throws InterruptedException {
   @Override
   public boolean tryLock() {
     String value = valueThreadLocal.get();
-    if (value == null || value.length() == 0) {
+    if (value == null || value.isEmpty()) {
       value = UUID.randomUUID().toString();
       valueThreadLocal.set(value);
     }
@@ -98,8 +98,8 @@ public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
   public void unlock() {
     if (valueThreadLocal.get() != null) {
       // 提示: 必须指定returnType, 类型: 此处必须为Long, 不能是Integer
-      RedisScript<Long> script = new DefaultRedisScript("if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end", Long.class);
-      redisTemplate.execute(script, Arrays.asList(key), valueThreadLocal.get());
+      RedisScript<Long> script = new DefaultRedisScript<>("if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end", Long.class);
+      redisTemplate.execute(script, Collections.singletonList(key), valueThreadLocal.get());
       valueThreadLocal.remove();
     }
   }
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/res/StringManager.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/res/StringManager.java
index e5bdb38804..fd2f13a553 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/res/StringManager.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/res/StringManager.java
@@ -102,7 +102,7 @@ private StringManager(String packageName, Locale locale) {
    *
    * @param packageName The package name
    */
-  public static final synchronized StringManager getManager(
+  public static synchronized StringManager getManager(
     String packageName) {
     return getManager(packageName, Locale.getDefault());
   }
@@ -115,7 +115,7 @@ public static final synchronized StringManager getManager(
    * @param packageName The package name
    * @param locale      The Locale
    */
-  public static final synchronized StringManager getManager(
+  public static synchronized StringManager getManager(
     String packageName, Locale locale) {
 
     Map<Locale, StringManager> map = MANAGERS.get(packageName);
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/IntegerArrayConverter.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/IntegerArrayConverter.java
index 3532fcab08..710547c746 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/IntegerArrayConverter.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/xml/IntegerArrayConverter.java
@@ -25,7 +25,7 @@ public String toString(Object obj) {
   @Override
   public Object fromString(String str) {
 
-    if (str == null || str.length() == 0) {
+    if (str == null || str.isEmpty()) {
       return null;
     }
 
diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/HttpResponseProxyTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/HttpResponseProxyTest.java
index 4d188b50bc..1b20b98d74 100644
--- a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/HttpResponseProxyTest.java
+++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/HttpResponseProxyTest.java
@@ -1,6 +1,7 @@
 package me.chanjar.weixin.common.util.http;
 
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.apache.ApacheHttpResponseProxy;
 import org.testng.annotations.Test;
 
 import static org.testng.Assert.*;
diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilderTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilderTest.java
index 08de63167b..7296d29d44 100644
--- a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilderTest.java
+++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilderTest.java
@@ -79,13 +79,13 @@ void testHttpClientWithInterceptor() throws Exception {
       HttpUriRequest request = new HttpGet("http://localhost:8080");
       HttpContext context = HttpClientContext.create();
       try (CloseableHttpResponse resp = client.execute(request, context)) {
-        Assert.assertEquals("requestInterceptor1", context.getAttribute("interceptor_called"), "成功调用 requestInterceptor1 并向 content 中写入了数据");
+        Assert.assertEquals(context.getAttribute("interceptor_called"), "requestInterceptor1", "成功调用 requestInterceptor1 并向 content 中写入了数据");
 
         // 测试拦截器执行顺序
-        Assert.assertEquals("requestInterceptor1", interceptorOrder.get(0));
-        Assert.assertEquals("requestInterceptor2", interceptorOrder.get(1));
-        Assert.assertEquals("responseInterceptor1", interceptorOrder.get(2));
-        Assert.assertEquals("responseInterceptor2", interceptorOrder.get(3));
+        Assert.assertEquals(interceptorOrder.get(0), "requestInterceptor1");
+        Assert.assertEquals(interceptorOrder.get(1), "requestInterceptor2");
+        Assert.assertEquals(interceptorOrder.get(2), "responseInterceptor1");
+        Assert.assertEquals(interceptorOrder.get(3), "responseInterceptor2");
       }
     }
   }
diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/SSLConfigurationTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/SSLConfigurationTest.java
new file mode 100644
index 0000000000..cecda5ca54
--- /dev/null
+++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/SSLConfigurationTest.java
@@ -0,0 +1,116 @@
+package me.chanjar.weixin.common.util.http.apache;
+
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 测试SSL配置，特别是TLS协议版本配置
+ * Test SSL configuration, especially TLS protocol version configuration
+ */
+public class SSLConfigurationTest {
+
+  @Test
+  public void testDefaultTLSProtocols() throws Exception {
+    // Create a new instance to check the default configuration
+    Class<?> builderClass = DefaultApacheHttpClientBuilder.class;
+    Object builder = builderClass.getDeclaredMethod("get").invoke(null);
+    
+    // 验证默认支持的TLS协议版本包含现代版本
+    Field supportedProtocolsField = builderClass.getDeclaredField("supportedProtocols");
+    supportedProtocolsField.setAccessible(true);
+    String[] supportedProtocols = (String[]) supportedProtocolsField.get(builder);
+    
+    List<String> protocolList = Arrays.asList(supportedProtocols);
+    
+    System.out.println("Default supported TLS protocols: " + Arrays.toString(supportedProtocols));
+    
+    // 主要验证：应该支持TLS 1.2和/或1.3 (现代安全版本)
+    // Main validation: Should support TLS 1.2 and/or 1.3 (modern secure versions)
+    Assert.assertTrue(protocolList.contains("TLSv1.2"), "Should support TLS 1.2");
+    Assert.assertTrue(protocolList.contains("TLSv1.3"), "Should support TLS 1.3");
+    
+    // 验证不再是只有TLS 1.0 (这是导致原问题的根本原因)
+    // Verify it's no longer just TLS 1.0 (which was the root cause of the original issue)
+    Assert.assertTrue(protocolList.size() > 0, "Should support at least one TLS version");
+    boolean hasModernTLS = protocolList.contains("TLSv1.2") || protocolList.contains("TLSv1.3");
+    Assert.assertTrue(hasModernTLS, "Should support at least one modern TLS version (1.2 or 1.3)");
+    
+    // 验证不是原来的老旧配置 (只有 "TLSv1")
+    // Verify it's not the old configuration (only "TLSv1")
+    boolean isOldConfig = protocolList.size() == 1 && protocolList.contains("TLSv1");
+    Assert.assertFalse(isOldConfig, "Should not be the old configuration that only supported TLS 1.0");
+  }
+
+  @Test
+  public void testCustomTLSProtocols() throws Exception {
+    // Test that we can set custom TLS protocols
+    String[] customProtocols = {"TLSv1.2", "TLSv1.3"};
+    
+    // Create a new builder instance using reflection to avoid singleton issues in testing
+    Class<?> builderClass = DefaultApacheHttpClientBuilder.class;
+    Constructor<?> constructor = builderClass.getDeclaredConstructor();
+    constructor.setAccessible(true);
+    Object builder = constructor.newInstance();
+    
+    // Set custom protocols
+    builderClass.getMethod("supportedProtocols", String[].class).invoke(builder, (Object) customProtocols);
+    
+    Field supportedProtocolsField = builderClass.getDeclaredField("supportedProtocols");
+    supportedProtocolsField.setAccessible(true);
+    String[] actualProtocols = (String[]) supportedProtocolsField.get(builder);
+    
+    Assert.assertEquals(actualProtocols, customProtocols, "Custom protocols should be set correctly");
+    
+    System.out.println("Custom supported TLS protocols: " + Arrays.toString(actualProtocols));
+  }
+
+  @Test
+  public void testSSLContextCreation() throws Exception {
+    DefaultApacheHttpClientBuilder builder = DefaultApacheHttpClientBuilder.get();
+    
+    // 构建HTTP客户端以验证SSL工厂是否正确创建
+    CloseableHttpClient client = builder.build();
+    Assert.assertNotNull(client, "HTTP client should be created successfully");
+    
+    // 验证SSL上下文支持现代TLS协议
+    SSLContext sslContext = SSLContext.getDefault();
+    SSLSocketFactory socketFactory = sslContext.getSocketFactory();
+    
+    // 创建一个SSL socket来检查支持的协议
+    try (SSLSocket socket = (SSLSocket) socketFactory.createSocket()) {
+      String[] supportedProtocols = socket.getSupportedProtocols();
+      List<String> supportedList = Arrays.asList(supportedProtocols);
+      
+      // JVM应该支持TLS 1.2（在JDK 8+中默认可用）
+      Assert.assertTrue(supportedList.contains("TLSv1.2"), 
+          "JVM should support TLS 1.2. Supported protocols: " + Arrays.toString(supportedProtocols));
+      
+      System.out.println("JVM supported TLS protocols: " + Arrays.toString(supportedProtocols));
+    }
+    
+    client.close();
+  }
+
+  @Test
+  public void testBuilderChaining() {
+    DefaultApacheHttpClientBuilder builder = DefaultApacheHttpClientBuilder.get();
+    
+    // 测试方法链调用
+    ApacheHttpClientBuilder result = builder
+        .supportedProtocols(new String[]{"TLSv1.2", "TLSv1.3"})
+        .httpProxyHost("proxy.example.com")
+        .httpProxyPort(8080);
+    
+    Assert.assertSame(result, builder, "Builder methods should return the same instance for method chaining");
+  }
+}
\ No newline at end of file
diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/SSLIntegrationTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/SSLIntegrationTest.java
new file mode 100644
index 0000000000..e732360e87
--- /dev/null
+++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/http/apache/SSLIntegrationTest.java
@@ -0,0 +1,73 @@
+package me.chanjar.weixin.common.util.http.apache;
+
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * 集成测试 - 验证SSL配置可以正常访问HTTPS网站
+ * Integration test - Verify SSL configuration can access HTTPS websites properly
+ */
+public class SSLIntegrationTest {
+
+  @Test
+  public void testHTTPSConnectionWithModernTLS() throws Exception {
+    DefaultApacheHttpClientBuilder builder = DefaultApacheHttpClientBuilder.get();
+    
+    // 使用默认配置（支持现代TLS版本）创建客户端
+    CloseableHttpClient client = builder.build();
+    
+    // 测试访问一个需要现代TLS的网站
+    // Test accessing a website that requires modern TLS
+    HttpGet httpGet = new HttpGet("https://api.weixin.qq.com/");
+    
+    try (CloseableHttpResponse response = client.execute(httpGet)) {
+      // 验证能够成功建立HTTPS连接（不管响应内容是什么）
+      // Verify that HTTPS connection can be established successfully (regardless of response content)
+      Assert.assertNotNull(response, "Should be able to establish HTTPS connection");
+      Assert.assertNotNull(response.getStatusLine(), "Should receive a status response");
+      
+      int statusCode = response.getStatusLine().getStatusCode();
+      // 任何HTTP状态码都表示SSL握手成功
+      // Any HTTP status code indicates successful SSL handshake
+      Assert.assertTrue(statusCode > 0, "Should receive a valid HTTP status code, got: " + statusCode);
+      
+      System.out.println("HTTPS connection test successful. Status: " + response.getStatusLine());
+    } catch (javax.net.ssl.SSLHandshakeException e) {
+      Assert.fail("SSL handshake should not fail with modern TLS configuration. Error: " + e.getMessage());
+    } finally {
+      client.close();
+    }
+  }
+
+  @Test 
+  public void testCustomTLSConfiguration() throws Exception {
+    DefaultApacheHttpClientBuilder builder = DefaultApacheHttpClientBuilder.get();
+    
+    // 配置为只支持TLS 1.2和1.3（最安全的配置）
+    // Configure to only support TLS 1.2 and 1.3 (most secure configuration)
+    builder.supportedProtocols(new String[]{"TLSv1.2", "TLSv1.3"});
+    
+    CloseableHttpClient client = builder.build();
+    
+    // 测试这个配置是否能正常工作
+    HttpGet httpGet = new HttpGet("https://httpbin.org/get");
+    
+    try (CloseableHttpResponse response = client.execute(httpGet)) {
+      Assert.assertNotNull(response, "Should be able to establish HTTPS connection with TLS 1.2/1.3");
+      int statusCode = response.getStatusLine().getStatusCode();
+      Assert.assertEquals(statusCode, 200, "Should get HTTP 200 response from httpbin.org");
+      
+      System.out.println("Custom TLS configuration test successful. Status: " + response.getStatusLine());
+    } catch (javax.net.ssl.SSLHandshakeException e) {
+      // 这个测试可能会因为网络环境而失败，所以我们只是记录警告
+      // This test might fail due to network environment, so we just log a warning
+      System.out.println("Warning: SSL handshake failed with custom TLS config: " + e.getMessage());
+      System.out.println("This might be due to network restrictions in the test environment.");
+    } finally {
+      client.close();
+    }
+  }
+}
\ No newline at end of file
diff --git a/weixin-java-cp/pom.xml b/weixin-java-cp/pom.xml
index 96fbcc8eea..19431d80a0 100644
--- a/weixin-java-cp/pom.xml
+++ b/weixin-java-cp/pom.xml
@@ -7,7 +7,7 @@
   <parent>
     <groupId>com.github.binarywang</groupId>
     <artifactId>wx-java</artifactId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
 
   <artifactId>weixin-java-cp</artifactId>
@@ -30,6 +30,11 @@
       <artifactId>okhttp</artifactId>
       <scope>provided</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.httpcomponents.client5</groupId>
+      <artifactId>httpclient5</artifactId>
+      <scope>provided</scope>
+    </dependency>
     <dependency>
       <groupId>redis.clients</groupId>
       <artifactId>jedis</artifactId>
@@ -84,7 +89,7 @@
     <dependency>
       <groupId>org.bouncycastle</groupId>
       <artifactId>bcprov-jdk18on</artifactId>
-      <version>1.78.1</version>
+      <version>1.80</version>
     </dependency>
 
     <dependency>
@@ -101,7 +106,6 @@
     <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-core</artifactId>
-      <version>2.13.4</version>
       <scope>test</scope>
     </dependency>
   </dependencies>
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpAgentWorkBenchService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpAgentWorkBenchService.java
index c50aa2f5fc..67c57a8a88 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpAgentWorkBenchService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpAgentWorkBenchService.java
@@ -36,4 +36,12 @@ public interface WxCpAgentWorkBenchService {
    * @throws WxErrorException the wx error exception
    */
   void setWorkBenchData(WxCpAgentWorkBench wxCpAgentWorkBench) throws WxErrorException;
+
+  /**
+   * Batch sets work bench data.
+   *
+   * @param wxCpAgentWorkBench the wx cp agent work bench
+   * @throws WxErrorException the wx error exception
+   */
+  void batchSetWorkBenchData(WxCpAgentWorkBench wxCpAgentWorkBench) throws WxErrorException;
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java
index 46d74bf92b..7f3cdeab7c 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpExternalContactService.java
@@ -1,5 +1,10 @@
 package me.chanjar.weixin.cp.api;
 
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Date;
+import java.util.List;
 import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.cp.bean.WxCpBaseResp;
@@ -11,12 +16,6 @@
 import me.chanjar.weixin.cp.bean.external.interceptrule.WxCpInterceptRuleInfo;
 import me.chanjar.weixin.cp.bean.external.interceptrule.WxCpInterceptRuleList;
 
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Date;
-import java.util.List;
-
 /**
  * <pre>
  * 外部联系人管理接口，企业微信的外部联系人的接口和通讯录接口已经拆离
@@ -39,6 +38,7 @@ public interface WxCpExternalContactService {
    * 用户需要妥善存储返回的config_id，config_id丢失可能导致用户无法编辑或删除「联系我」。
    * 临时会话模式不占用「联系我」数量，但每日最多添加10万个，并且仅支持单人。
    * 临时会话模式的二维码，添加好友完成后该二维码即刻失效。
+   * <a href="https://developer.work.weixin.qq.com/document/path/92228">文档地址</a>
    * </pre>
    *
    * @param info 客户联系「联系我」方式
@@ -60,6 +60,25 @@ public interface WxCpExternalContactService {
    */
   WxCpContactWayInfo getContactWay(String configId) throws WxErrorException;
 
+  /**
+   * 获取企业已配置的「联系我」列表
+   *
+   * <pre>
+   * 获取企业配置的「联系我」二维码和「联系我」小程序插件列表。不包含临时会话。
+   * 注意，<b>该接口仅可获取2021年7月10日以后创建的「联系我」</b>
+   * </pre>
+   *
+   * 文档地址: <a href="https://developer.work.weixin.qq.com/document/path/92228#%E8%8E%B7%E5%8F%96%E4%BC%81%E4%B8%9A%E5%B7%B2%E9%85%8D%E7%BD%AE%E7%9A%84%E3%80%8C%E8%81%94%E7%B3%BB%E6%88%91%E3%80%8D%E5%88%97%E8%A1%A8">获取企业已配置的「联系我」列表</a>
+   *
+   * @param startTime 「联系我」创建起始时间戳, 默认为90天前
+   * @param endTime 「联系我」创建结束时间戳, 默认为当前时间
+   * @param cursor 分页查询使用的游标，为上次请求返回的 next_cursor
+   * @param limit 每次查询的分页大小，默认为100条，最多支持1000条
+   * @return contact way configId
+   * @throws WxErrorException the wx error exception
+   */
+  WxCpContactWayList listContactWay(Long startTime, Long endTime, String cursor, Long limit) throws WxErrorException;
+
   /**
    * 更新企业已配置的「联系我」方式
    *
@@ -381,6 +400,24 @@ WxCpExternalContactBatchInfo getContactDetailBatch(String[] userIdList, String c
                                                      Integer limit)
     throws WxErrorException;
 
+  /**
+   * 获取已服务的外部联系人
+   * <pre>
+   *  企业可通过此接口获取所有已服务的外部联系人，及其添加人和加入的群聊。
+   * 外部联系人分为客户和其他外部联系人，如果是客户，接口将返回外部联系人临时ID和externaluserid；如果是其他外部联系人，接口将只返回外部联系人临时ID。
+   * 请求方式：POST（HTTPS）
+   * 请求地址：https://qyapi.weixin.qq.com/cgi-bin/externalcontact/contact_list?access_token=ACCESS_TOKEN
+   * 文档地址: https://developer.work.weixin.qq.com/document/path/99434
+   * </pre>
+   *
+   * @param cursor     the cursor
+   * @param limit      the  limit
+   * @return 已服务的外部联系人列表
+   * @throws WxErrorException .
+   * @apiNote 企业可通过外部联系人临时ID排除重复数据，外部联系人临时ID有效期为4小时。
+   */
+  WxCpExternalContactListInfo getContactList(String cursor, Integer limit) throws WxErrorException;
+
   /**
    * 修改客户备注信息.
    * <pre>
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpKfService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpKfService.java
index 86b342f2fc..5a53829dc0 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpKfService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpKfService.java
@@ -75,6 +75,19 @@ public interface WxCpKfService {
    */
   WxCpKfServicerOpResp addServicer(String openKfid, List<String> userIdList) throws WxErrorException;
 
+  /**
+   * 接待人员管理
+   * 添加指定客服账号的接待人员，每个客服账号目前最多可添加2000个接待人员，20个部门。
+   * userid_list和department_id_list至少需要填其中一个
+   *
+   * @param openKfid   客服帐号ID
+   * @param userIdList 接待人员userid列表。第三方应用填密文userid，即open_userid 可填充个数：1 ~ 100。超过100个需分批调用。
+   * @param departmentIdList 接待人员部门id列表 可填充个数：0 ~ 20。
+   * @return 添加客服账号结果 wx cp kf servicer op resp
+   * @throws WxErrorException 异常
+   */
+  WxCpKfServicerOpResp addServicer(String openKfid, List<String> userIdList,List<String> departmentIdList) throws WxErrorException;
+
   /**
    * 接待人员管理
    * 从客服帐号删除接待人员
@@ -86,6 +99,19 @@ public interface WxCpKfService {
    */
   WxCpKfServicerOpResp delServicer(String openKfid, List<String> userIdList) throws WxErrorException;
 
+  /**
+   * 接待人员管理
+   * 从客服帐号删除接待人员
+   * userid_list和department_id_list至少需要填其中一个
+   *
+   * @param openKfid   客服帐号ID
+   * @param userIdList 接待人员userid列表。第三方应用填密文userid，即open_userid 可填充个数：1 ~ 100。超过100个需分批调用。
+   * @param departmentIdList 接待人员部门id列表 可填充个数：0 ~ 100。超过100个需分批调用。
+   * @return 删除客服账号结果 wx cp kf servicer op resp
+   * @throws WxErrorException 异常
+   */
+  WxCpKfServicerOpResp delServicer(String openKfid, List<String> userIdList, List<String> departmentIdList) throws WxErrorException;
+
   /**
    * 接待人员管理
    * 获取某个客服帐号的接待人员列表
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java
index 82f6db9178..e874b26f42 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java
@@ -2,6 +2,8 @@
 
 import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.cp.bean.media.MediaUploadByUrlReq;
+import me.chanjar.weixin.cp.bean.media.MediaUploadByUrlResult;
 
 import java.io.File;
 import java.io.IOException;
@@ -133,4 +135,21 @@ WxMediaUploadResult upload(String mediaType, String filename, String url)
    * @throws WxErrorException the wx error exception
    */
   String uploadImg(File file) throws WxErrorException;
+
+  /**
+   * 生成异步上传任务
+   * 跟上传临时素材拿到的media_id使用场景是不通用的，目前适配的接口如下：https://developer.work.weixin.qq.com/document/path/96488#%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF%E8%AF%B4%E6%98%8E
+   * @param req 请求参数
+   * @return 返回异步任务id
+   * @throws WxErrorException the wx error exception
+   */
+  String uploadByUrl(MediaUploadByUrlReq req) throws WxErrorException;
+
+  /**
+   * 查询异步任务结果
+   * @param jobId 任务id。最长为128字节，60分钟内有效
+   * @return 返回异步任务结果
+   * @throws WxErrorException the wx error exception
+   */
+  MediaUploadByUrlResult uploadByUrl(String jobId) throws WxErrorException;
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMeetingService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMeetingService.java
index e3ee866118..d761f99d0b 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMeetingService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMeetingService.java
@@ -5,8 +5,6 @@
 import me.chanjar.weixin.cp.bean.oa.meeting.WxCpMeetingUpdateResult;
 import me.chanjar.weixin.cp.bean.oa.meeting.WxCpUserMeetingIdResult;
 
-import java.util.List;
-
 /**
  * 企业微信日程接口.
  * 企业和开发者通过会议接口可以便捷地预定及管理会议，用于小组周会、部门例会等场景。
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaService.java
index 4647e0ed3f..ee57107b5c 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaService.java
@@ -22,7 +22,7 @@ public interface WxCpOaService {
    *
    * 请求方式：POST（HTTPS）
    * 请求地址： https://qyapi.weixin.qq.com/cgi-bin/oa/applyevent?access_token=ACCESS_TOKEN
-   * 文档地址：https://work.weixin.qq.com/api/doc/90000/90135/91853
+   * <a href="https://work.weixin.qq.com/api/doc/90000/90135/91853">文档地址</a>
    * </pre>
    *
    * @param request 请求
@@ -34,7 +34,7 @@ public interface WxCpOaService {
   /**
    * <pre>
    *  获取打卡数据
-   *  API doc : https://work.weixin.qq.com/api/doc#90000/90135/90262
+   *  <a href="https://work.weixin.qq.com/api/doc#90000/90135/90262">文档地址</a>
    * </pre>
    *
    * @param openCheckinDataType 打卡类型。1：上下班打卡；2：外出打卡；3：全部打卡
@@ -50,7 +50,7 @@ List<WxCpCheckinData> getCheckinData(Integer openCheckinDataType, Date startTime
   /**
    * <pre>
    *   获取打卡规则
-   *   API doc : https://work.weixin.qq.com/api/doc#90000/90135/90263
+   *  <a href="https://work.weixin.qq.com/api/doc#90000/90135/90263">文档地址</a>
    * </pre>
    *
    * @param datetime   需要获取规则的当天日期
@@ -64,7 +64,7 @@ List<WxCpCheckinData> getCheckinData(Integer openCheckinDataType, Date startTime
   /**
    * <pre>
    *   获取企业所有打卡规则
-   *   API doc : https://work.weixin.qq.com/api/doc/90000/90135/93384
+   * <a href="https://work.weixin.qq.com/api/doc/90000/90135/93384">文档地址</a>
    * </pre>
    *
    * @return 打卡规则列表 crop checkin option
@@ -82,7 +82,7 @@ List<WxCpCheckinData> getCheckinData(Integer openCheckinDataType, Date startTime
    *
    * 一次拉取调用最多拉取100个审批记录，可以通过多次拉取的方式来满足需求，但调用频率不可超过600次/分。
    *
-   * API doc : https://work.weixin.qq.com/api/doc/90000/90135/91816
+   * <a href="https://work.weixin.qq.com/api/doc/90000/90135/91816">文档地址</a>
    * </pre>
    *
    * @param startTime 开始时间
@@ -121,7 +121,7 @@ WxCpApprovalInfo getApprovalInfo(@NonNull Date startTime, @NonNull Date endTime,
    *
    * 一次拉取调用最多拉取100个审批记录，可以通过多次拉取的方式来满足需求，但调用频率不可超过600次/分。
    *
-   * API doc : https://work.weixin.qq.com/api/doc/90000/90135/91816
+   * <a href="https://work.weixin.qq.com/api/doc/90000/90135/91816">文档地址</a>
    *
    * 1 接口频率限制 600次/分钟
    * 2 请求的参数endtime需要大于startime， 起始时间跨度不能超过31天；
@@ -146,7 +146,7 @@ WxCpApprovalInfo getApprovalInfo(@NonNull Date startTime, @NonNull Date endTime,
    *
    *   企业可通过审批应用或自建应用Secret调用本接口，根据审批单号查询企业微信“审批应用”的审批申请详情。
    *
-   *   API Doc : https://work.weixin.qq.com/api/doc/90000/90135/91983
+   *  <a href="https://work.weixin.qq.com/api/doc/90000/90135/91983">文档地址</a>
    * </pre>
    *
    * @param spNo 审批单编号。
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaWeDriveService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaWeDriveService.java
index ad2dc635fc..e7217616b8 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaWeDriveService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpOaWeDriveService.java
@@ -9,7 +9,7 @@
 
 /**
  * 企业微信微盘相关接口.
- * https://developer.work.weixin.qq.com/document/path/93654
+ * <a href="https://developer.work.weixin.qq.com/document/path/93654">...</a>
  *
  * @author <a href="https://github.com/0katekate0">Wang_Wong</a> created on  2022-04-22
  */
@@ -20,7 +20,7 @@ public interface WxCpOaWeDriveService {
    * 该接口用于在微盘内新建空间，可以指定人创建空间。
    * <p>
    * 请求方式：POST（HTTPS）
-   * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/wedrive/space_create?access_token=ACCESS_TOKEN
+   * 请求地址: <a href="https://qyapi.weixin.qq.com/cgi-bin/wedrive/space_create?access_token=ACCESS_TOKEN">...</a>
    *
    * @param request 新建空间对应请求参数
    * @return spaceid （空间id）
@@ -33,7 +33,7 @@ public interface WxCpOaWeDriveService {
    * 该接口用于重命名已有空间，接收userid参数，以空间管理员身份来重命名。
    * <p>
    * 请求方式：POST（HTTPS）
-   * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/wedrive/space_rename?access_token=ACCESS_TOKEN
+   * 请求地址: <a href="https://qyapi.weixin.qq.com/cgi-bin/wedrive/space_rename?access_token=ACCESS_TOKEN">...</a>
    *
    * @param request 重命名空间的请求参数
    * @return wx cp base resp
@@ -46,35 +46,33 @@ public interface WxCpOaWeDriveService {
    * 该接口用于解散已有空间，需要以空间管理员身份来解散。
    * <p>
    * 请求方式：POST（HTTPS）
-   * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/wedrive/space_dismiss?access_token=ACCESS_TOKEN
+   * 请求地址: <a href="https://qyapi.weixin.qq.com/cgi-bin/wedrive/space_dismiss?access_token=ACCESS_TOKEN">...</a>
    *
-   * @param userId  the user id
    * @param spaceId the space id
    * @return wx cp base resp
    * @throws WxErrorException the wx error exception
    */
-  WxCpBaseResp spaceDismiss(@NonNull String userId, @NonNull String spaceId) throws WxErrorException;
+  WxCpBaseResp spaceDismiss(@NonNull String spaceId) throws WxErrorException;
 
   /**
    * 获取空间信息
    * 该接口用于获取空间成员列表、信息、权限等信息。
    * <p>
    * 请求方式：POST（HTTPS）
-   * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/wedrive/space_info?access_token=ACCESS_TOKEN
+   * 请求地址: <a href="https://qyapi.weixin.qq.com/cgi-bin/wedrive/space_info?access_token=ACCESS_TOKEN">...</a>
    *
-   * @param userId  the user id
    * @param spaceId the space id
    * @return wx cp space info
    * @throws WxErrorException the wx error exception
    */
-  WxCpSpaceInfo spaceInfo(@NonNull String userId, @NonNull String spaceId) throws WxErrorException;
+  WxCpSpaceInfo spaceInfo(@NonNull String spaceId) throws WxErrorException;
 
   /**
    * 添加成员/部门
    * 该接口用于对指定空间添加成员/部门，可一次性添加多个。
    * <p>
    * 请求方式：POST（HTTPS）
-   * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/wedrive/space_acl_add?access_token=ACCESS_TOKEN
+   * 请求地址: <a href="https://qyapi.weixin.qq.com/cgi-bin/wedrive/space_acl_add?access_token=ACCESS_TOKEN">...</a>
    *
    * @param request 添加成员/部门请求参数
    * @return wx cp base resp
@@ -87,7 +85,7 @@ public interface WxCpOaWeDriveService {
    * 该接口用于对指定空间移除成员/部门，操作者需要有移除权限。
    * <p>
    * 请求方式：POST（HTTPS）
-   * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/wedrive/space_acl_del?access_token=ACCESS_TOKEN
+   * 请求地址: <a href="https://qyapi.weixin.qq.com/cgi-bin/wedrive/space_acl_del?access_token=ACCESS_TOKEN">...</a>
    *
    * @param request 移除成员/部门请求参数
    * @return wx cp base resp
@@ -100,7 +98,7 @@ public interface WxCpOaWeDriveService {
    * 该接口用于修改空间权限，需要传入userid，修改权限范围继承传入用户的权限范围。
    * <p>
    * 请求方式：POST（HTTPS）
-   * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/wedrive/space_setting?access_token=ACCESS_TOKEN
+   * 请求地址: <a href="https://qyapi.weixin.qq.com/cgi-bin/wedrive/space_setting?access_token=ACCESS_TOKEN">...</a>
    *
    * @param request 权限管理请求参数
    * @return wx cp base resp
@@ -113,21 +111,20 @@ public interface WxCpOaWeDriveService {
    * 该接口用于获取空间邀请分享链接。
    * <p>
    * 请求方式：POST（HTTPS）
-   * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/wedrive/space_share?access_token=ACCESS_TOKEN
+   * 请求地址: <a href="https://qyapi.weixin.qq.com/cgi-bin/wedrive/space_share?access_token=ACCESS_TOKEN">...</a>
    *
-   * @param userId  the user id
    * @param spaceId the space id
    * @return wx cp space share
    * @throws WxErrorException the wx error exception
    */
-  WxCpSpaceShare spaceShare(@NonNull String userId, @NonNull String spaceId) throws WxErrorException;
+  WxCpSpaceShare spaceShare(@NonNull String spaceId) throws WxErrorException;
 
   /**
    * 获取文件列表
    * 该接口用于获取指定地址下的文件列表。
    * <p>
    * 请求方式：POST（HTTPS）
-   * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_list?access_token=ACCESS_TOKEN
+   * 请求地址: <a href="https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_list?access_token=ACCESS_TOKEN">...</a>
    *
    * @param request 获取文件列表请求参数
    * @return wx cp file list
@@ -140,7 +137,7 @@ public interface WxCpOaWeDriveService {
    * 该接口用于向微盘中的指定位置上传文件。
    * <p>
    * 请求方式：POST（HTTPS）
-   * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_upload?access_token=ACCESS_TOKEN
+   * 请求地址: <a href="https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_upload?access_token=ACCESS_TOKEN">...</a>
    *
    * @param request 上传文件请求参数
    * @return wx cp file upload
@@ -153,54 +150,58 @@ public interface WxCpOaWeDriveService {
    * 该接口用于下载文件，请求的userid需有下载权限。
    * <p>
    * 请求方式：POST（HTTPS）
-   * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_download?access_token=ACCESS_TOKEN
+   * 请求地址: <a href="https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_download?access_token=ACCESS_TOKEN">...</a>
    *
-   * @param userId the user id
-   * @param fileId the file id
-   * @return wx cp file download
+   * @param fileId         文件fileid（只支持下载普通文件，不支持下载文件夹或微文档）
+   * @param selectedTicket 微盘和文件选择器jsapi返回的selectedTicket。若填此参数，则不需要填fileid。
+   * @return {
+   * "errcode": 0,
+   * "errmsg": "ok",
+   * "download_url": "DOWNLOAD_URL",
+   * "cookie_name": "COOKIE_NAME",
+   * "cookie_value": "COOKIE_VALUE"
+   * }
    * @throws WxErrorException the wx error exception
    */
-  WxCpFileDownload fileDownload(@NonNull String userId, @NonNull String fileId) throws WxErrorException;
+  WxCpFileDownload fileDownload(String fileId, String selectedTicket) throws WxErrorException;
 
   /**
    * 重命名文件
    * 该接口用于对指定文件进行重命名。
    * <p>
    * 请求方式：POST（HTTPS）
-   * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_rename?access_token=ACCESS_TOKEN
+   * 请求地址: <a href="https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_rename?access_token=ACCESS_TOKEN">...</a>
    *
-   * @param userId  the user id
    * @param fileId  the file id
    * @param newName the new name
    * @return wx cp file rename
    * @throws WxErrorException the wx error exception
    */
-  WxCpFileRename fileRename(@NonNull String userId, @NonNull String fileId, @NonNull String newName) throws WxErrorException;
+  WxCpFileRename fileRename(@NonNull String fileId, @NonNull String newName) throws WxErrorException;
 
   /**
-   * 新建文件/微文档
-   * 该接口用于在微盘指定位置新建文件、微文档。
+   * 新建文件夹/文档
+   * 该接口用于在微盘指定位置新建文件夹、文档（更多文档接口能力可见文档API接口说明）。
    * <p>
    * 请求方式：POST（HTTPS）
-   * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_create?access_token=ACCESS_TOKEN
+   * 请求地址: <a href="https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_create?access_token=ACCESS_TOKEN">...</a>
    *
-   * @param userId   操作者userid
    * @param spaceId  空间spaceid
    * @param fatherId 父目录fileid, 在根目录时为空间spaceid
-   * @param fileType 文件类型, 1:文件夹 3:微文档(文档) 4:微文档(表格)
-   * @param fileName 文件名字
+   * @param fileType 文件类型, 1:文件夹 3:文档(文档) 4:文档(表格)
+   * @param fileName 文件名字（注意：文件名最多填255个字符, 英文算1个, 汉字算2个）
    * @return wx cp file create
    * @throws WxErrorException the wx error exception
    */
-  WxCpFileCreate fileCreate(@NonNull String userId, @NonNull String spaceId,
-                            @NonNull String fatherId, @NonNull Integer fileType, @NonNull String fileName) throws WxErrorException;
+  WxCpFileCreate fileCreate(@NonNull String spaceId, @NonNull String fatherId, @NonNull Integer fileType,
+                            @NonNull String fileName) throws WxErrorException;
 
   /**
    * 移动文件
    * 该接口用于将文件移动到指定位置。
    * <p>
    * 请求方式：POST（HTTPS）
-   * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_move?access_token=ACCESS_TOKEN
+   * 请求地址: <a href="https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_move?access_token=ACCESS_TOKEN">...</a>
    *
    * @param request 移动文件的请求参数
    * @return wx cp file move
@@ -213,21 +214,33 @@ WxCpFileCreate fileCreate(@NonNull String userId, @NonNull String spaceId,
    * 该接口用于删除指定文件。
    * <p>
    * 请求方式：POST（HTTPS）
-   * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_delete?access_token=ACCESS_TOKEN
+   * 请求地址: <a href="https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_delete?access_token=ACCESS_TOKEN">...</a>
    *
-   * @param userId 操作者userid
-   * @param fileId 文件fileid列表
+   * @param fileIds 文件fileid列表
    * @return wx cp base resp
    * @throws WxErrorException the wx error exception
    */
-  WxCpBaseResp fileDelete(@NonNull String userId, @NonNull List<String> fileId) throws WxErrorException;
+  WxCpBaseResp fileDelete(@NonNull List<String> fileIds) throws WxErrorException;
+
+  /**
+   * 文件信息
+   * 该接口用于获取指定文件的信息。
+   * <p>
+   * 请求方式：POST（HTTPS）
+   * 请求地址: <a href="https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_info?access_token=ACCESS_TOKEN">...</a>
+   *
+   * @param fileId the file id
+   * @return wx cp file info
+   * @throws WxErrorException the wx error exception
+   */
+  WxCpFileInfo fileInfo(@NonNull String fileId) throws WxErrorException;
 
   /**
    * 新增指定人
    * 该接口用于对指定文件添加指定人/部门。
    * <p>
    * 请求方式：POST（HTTPS）
-   * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_acl_add?access_token=ACCESS_TOKEN
+   * 请求地址: <a href="https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_acl_add?access_token=ACCESS_TOKEN">...</a>
    *
    * @param request 新增指定人请求参数
    * @return wx cp base resp
@@ -240,7 +253,7 @@ WxCpFileCreate fileCreate(@NonNull String userId, @NonNull String spaceId,
    * 该接口用于删除指定文件的指定人/部门。
    * <p>
    * 请求方式：POST（HTTPS）
-   * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_acl_del?access_token=ACCESS_TOKEN
+   * 请求地址: <a href="https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_acl_del?access_token=ACCESS_TOKEN">...</a>
    *
    * @param request 请求参数
    * @return wx cp base resp
@@ -253,43 +266,27 @@ WxCpFileCreate fileCreate(@NonNull String userId, @NonNull String spaceId,
    * 该接口用于文件的分享设置。
    * <p>
    * 请求方式：POST（HTTPS）
-   * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_setting?access_token=ACCESS_TOKEN
+   * 请求地址: <a href="https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_setting?access_token=ACCESS_TOKEN">...</a>
    *
-   * @param userId    the user id
    * @param fileId    the file id
    * @param authScope the auth scope
    * @param auth      the auth
    * @return wx cp base resp
    * @throws WxErrorException the wx error exception
    */
-  WxCpBaseResp fileSetting(@NonNull String userId, @NonNull String fileId, @NonNull Integer authScope, Integer auth) throws WxErrorException;
+  WxCpBaseResp fileSetting(@NonNull String fileId, @NonNull Integer authScope, Integer auth) throws WxErrorException;
 
   /**
    * 获取分享链接
    * 该接口用于获取文件的分享链接。
    * <p>
    * 请求方式：POST（HTTPS）
-   * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_share?access_token=ACCESS_TOKEN
+   * 请求地址: <a href="https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_share?access_token=ACCESS_TOKEN">...</a>
    *
-   * @param userId the user id
    * @param fileId the file id
    * @return wx cp file share
    * @throws WxErrorException the wx error exception
    */
-  WxCpFileShare fileShare(@NonNull String userId, @NonNull String fileId) throws WxErrorException;
-
-  /**
-   * 文件信息
-   * 该接口用于获取指定文件的信息。
-   * <p>
-   * 请求方式：POST（HTTPS）
-   * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/wedrive/file_info?access_token=ACCESS_TOKEN
-   *
-   * @param userId the user id
-   * @param fileId the file id
-   * @return wx cp file info
-   * @throws WxErrorException the wx error exception
-   */
-  WxCpFileInfo fileInfo(@NonNull String userId, @NonNull String fileId) throws WxErrorException;
+  WxCpFileShare fileShare(@NonNull String fileId) throws WxErrorException;
 
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpSchoolUserService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpSchoolUserService.java
index 26cfe3a019..a92bfcc100 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpSchoolUserService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpSchoolUserService.java
@@ -334,7 +334,7 @@ WxCpBaseResp updateStudent(@NonNull String studentUserId, String newStudentUserI
    * 请求方式：GET（HTTPS）
    * 请求地址：https://qyapi.weixin.qq.com/cgi-bin/school/department/list?access_token=ACCESS_TOKEN&id=ID
    *
-   * @param id the id
+   * @param id 部门id。获取指定部门及其下的子部门。 如果不填，默认获取全量组织架构
    * @return wx cp department list
    * @throws WxErrorException the wx error exception
    */
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java
index f613f6138c..d0b7441d90 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java
@@ -110,7 +110,7 @@ public boolean checkSignature(String msgSignature, String timestamp, String nonc
       return SHA1.gen(this.configStorage.getToken(), timestamp, nonce, data)
         .equals(msgSignature);
     } 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;
     }
   }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentWorkBenchServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentWorkBenchServiceImpl.java
index bb5c191e96..b0bbb38642 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentWorkBenchServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpAgentWorkBenchServiceImpl.java
@@ -38,4 +38,10 @@ public void setWorkBenchData(WxCpAgentWorkBench wxCpAgentWorkBench) throws WxErr
     final String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WORKBENCH_DATA_SET));
     this.mainService.post(url, wxCpAgentWorkBench.toUserDataString());
   }
+
+  @Override
+  public void batchSetWorkBenchData(WxCpAgentWorkBench wxCpAgentWorkBench) throws WxErrorException {
+    final String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WORKBENCH_BATCH_DATA_SET));
+    this.mainService.post(url, wxCpAgentWorkBench.toBatchUserDataString());
+  }
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpCorpGroupServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpCorpGroupServiceImpl.java
index be754f229b..48bd952a83 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpCorpGroupServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpCorpGroupServiceImpl.java
@@ -8,7 +8,6 @@
 import me.chanjar.weixin.cp.api.WxCpCorpGroupService;
 import me.chanjar.weixin.cp.api.WxCpService;
 import me.chanjar.weixin.cp.bean.corpgroup.WxCpCorpGroupCorp;
-import me.chanjar.weixin.cp.bean.corpgroup.WxCpCorpGroupCorpListAppShareInfoResp;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
 import java.util.List;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java
index 8a7328af25..8e3a8d7b95 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImpl.java
@@ -1,7 +1,16 @@
 package me.chanjar.weixin.cp.api.impl;
 
+import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.ExternalContact.*;
+
 import com.google.gson.Gson;
 import com.google.gson.JsonObject;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
@@ -26,16 +35,6 @@
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
 
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.UUID;
-
-import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.ExternalContact.*;
-
 /**
  * The type Wx cp external contact service.
  *
@@ -66,6 +65,17 @@ public WxCpContactWayInfo getContactWay(String configId) throws WxErrorException
     return WxCpContactWayInfo.fromJson(this.mainService.post(url, json.toString()));
   }
 
+  @Override
+  public WxCpContactWayList listContactWay(Long startTime, Long endTime, String cursor, Long limit) throws WxErrorException {
+    JsonObject json = new JsonObject();
+    json.addProperty("start_time", startTime);
+    json.addProperty("end_time", endTime);
+    json.addProperty("cursor", cursor);
+    json.addProperty("limit", limit);
+    final String url = this.mainService.getWxCpConfigStorage().getApiUrl(LIST_CONTACT_WAY);
+    return WxCpContactWayList.fromJson(this.mainService.post(url, json.toString()));
+  }
+
   @Override
   public WxCpBaseResp updateContactWay(WxCpContactWayInfo info) throws WxErrorException {
     if (StringUtils.isBlank(info.getContactWay().getConfigId())) {
@@ -215,6 +225,20 @@ public WxCpExternalContactBatchInfo getContactDetailBatch(String[] userIdList, S
     return WxCpExternalContactBatchInfo.fromJson(responseContent);
   }
 
+  @Override
+  public WxCpExternalContactListInfo getContactList(String cursor, Integer limit) throws WxErrorException {
+    final String url = this.mainService.getWxCpConfigStorage().getApiUrl(GET_CONTACT_LIST);
+    JsonObject json = new JsonObject();
+    if (StringUtils.isNotBlank(cursor)) {
+      json.addProperty("cursor", cursor);
+    }
+    if (limit != null) {
+      json.addProperty("limit", limit);
+    }
+    String responseContent = this.mainService.post(url, json.toString());
+    return WxCpExternalContactListInfo.fromJson(responseContent);
+  }
+
   @Override
   public void updateRemark(WxCpUpdateRemarkRequest request) throws WxErrorException {
     final String url = this.mainService.getWxCpConfigStorage().getApiUrl(UPDATE_REMARK);
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpKfServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpKfServiceImpl.java
index 29e84c516f..be4f2a5850 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpKfServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpKfServiceImpl.java
@@ -70,23 +70,62 @@ public WxCpKfAccountLinkResp getAccountLink(WxCpKfAccountLink link) throws WxErr
 
   @Override
   public WxCpKfServicerOpResp addServicer(String openKfid, List<String> userIdList) throws WxErrorException {
-    return servicerOp(openKfid, userIdList, SERVICER_ADD);
+    return servicerOp(openKfid, userIdList, null, SERVICER_ADD);
+  }
+
+  @Override
+  public WxCpKfServicerOpResp addServicer(String openKfId, List<String> userIdList, List<String> departmentIdList) throws WxErrorException {
+    validateParameters(SERVICER_ADD, userIdList, departmentIdList);
+    return servicerOp(openKfId, userIdList, departmentIdList, SERVICER_ADD);
   }
 
   @Override
   public WxCpKfServicerOpResp delServicer(String openKfid, List<String> userIdList) throws WxErrorException {
-    return servicerOp(openKfid, userIdList, SERVICER_DEL);
+    return servicerOp(openKfid, userIdList, null, SERVICER_DEL);
   }
 
-  private WxCpKfServicerOpResp servicerOp(String openKfid, List<String> userIdList, String uri) throws WxErrorException {
+  @Override
+  public WxCpKfServicerOpResp delServicer(String openKfid, List<String> userIdList, List<String> departmentIdList) throws WxErrorException {
+    validateParameters(SERVICER_DEL, userIdList, departmentIdList);
+    return servicerOp(openKfid, userIdList, departmentIdList, SERVICER_DEL);
+  }
+
+  private void validateParameters(String uri, List<String> userIdList, List<String> departmentIdList) {
+    if ((userIdList == null || userIdList.isEmpty()) && (departmentIdList == null || departmentIdList.isEmpty())) {
+      throw new IllegalArgumentException("userid_list和department_id_list至少需要填其中一个");
+    }
+    if (SERVICER_DEL.equals(uri)) {
+      if (userIdList != null && userIdList.size() > 100) {
+        throw new IllegalArgumentException("可填充个数：0 ~ 100。超过100个需分批调用。");
+      }
+      if (departmentIdList != null && departmentIdList.size() > 100) {
+        throw new IllegalArgumentException("可填充个数：0 ~ 100。超过100个需分批调用。");
+      }
+    } else {
+      if (userIdList != null && userIdList.size() > 100) {
+        throw new IllegalArgumentException("可填充个数：0 ~ 100。超过100个需分批调用。");
+      }
+      if (departmentIdList != null && departmentIdList.size() > 20) {
+        throw new IllegalArgumentException("可填充个数：0 ~ 20。");
+      }
+    }
+  }
+
+  private WxCpKfServicerOpResp servicerOp(String openKfid, List<String> userIdList, List<String> departmentIdList, String uri) throws WxErrorException {
     String url = cpService.getWxCpConfigStorage().getApiUrl(uri);
 
     JsonObject json = new JsonObject();
     json.addProperty("open_kfid", openKfid);
-    JsonArray userIdArray = new JsonArray();
-    userIdList.forEach(userIdArray::add);
-    json.add("userid_list", userIdArray);
-
+    if (userIdList != null && !userIdList.isEmpty()) {
+      JsonArray userIdArray = new JsonArray();
+      userIdList.forEach(userIdArray::add);
+      json.add("userid_list", userIdArray);
+    }
+    if (departmentIdList != null && !departmentIdList.isEmpty()) {
+      JsonArray departmentIdArray = new JsonArray();
+      departmentIdList.forEach(departmentIdArray::add);
+      json.add("department_id_list", departmentIdArray);
+    }
     String responseContent = cpService.post(url, json.toString());
     return WxCpKfServicerOpResp.fromJson(responseContent);
   }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java
index 863dd7c1d4..a128a35ccb 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java
@@ -1,5 +1,6 @@
 package me.chanjar.weixin.cp.api.impl;
 
+import com.google.gson.JsonObject;
 import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
 import me.chanjar.weixin.common.error.WxErrorException;
@@ -9,8 +10,13 @@
 import me.chanjar.weixin.common.util.http.InputStreamData;
 import me.chanjar.weixin.common.util.http.MediaInputStreamUploadRequestExecutor;
 import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
+import me.chanjar.weixin.common.util.json.GsonHelper;
+import me.chanjar.weixin.common.util.json.GsonParser;
 import me.chanjar.weixin.cp.api.WxCpMediaService;
 import me.chanjar.weixin.cp.api.WxCpService;
+import me.chanjar.weixin.cp.bean.media.MediaUploadByUrlReq;
+import me.chanjar.weixin.cp.bean.media.MediaUploadByUrlResult;
+import org.apache.commons.io.IOUtils;
 
 import java.io.File;
 import java.io.IOException;
@@ -20,7 +26,12 @@
 import java.nio.file.Files;
 import java.util.UUID;
 
-import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Media.*;
+import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Media.GET_UPLOAD_BY_URL_RESULT;
+import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Media.IMG_UPLOAD;
+import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Media.JSSDK_MEDIA_GET;
+import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Media.MEDIA_GET;
+import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Media.MEDIA_UPLOAD;
+import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Media.UPLOAD_BY_URL;
 
 /**
  * <pre>
@@ -57,12 +68,7 @@ public WxMediaUploadResult upload(String mediaType, String filename, String url)
         , this.mainService.getWxCpConfigStorage().getApiUrl(MEDIA_UPLOAD + mediaType),
         new InputStreamData(inputStream, filename));
     } finally {
-      if (inputStream != null) {
-        try {
-          inputStream.close();
-        } catch (IOException e) {
-        }
-      }
+      IOUtils.closeQuietly(inputStream);
       if (conn != null) {
         conn.disconnect();
       }
@@ -119,4 +125,20 @@ public String uploadImg(File file) throws WxErrorException {
     return this.mainService.execute(MediaUploadRequestExecutor.create(this.mainService.getRequestHttp()), url, file)
       .getUrl();
   }
+
+  @Override
+  public String uploadByUrl(MediaUploadByUrlReq req) throws WxErrorException {
+    final String url = this.mainService.getWxCpConfigStorage().getApiUrl(UPLOAD_BY_URL);
+    String responseContent = this.mainService.post(url, req.toJson());
+    return GsonHelper.getString(GsonParser.parse(responseContent), "jobid");
+  }
+
+  @Override
+  public MediaUploadByUrlResult uploadByUrl(String jobId) throws WxErrorException {
+    final String url = this.mainService.getWxCpConfigStorage().getApiUrl(GET_UPLOAD_BY_URL_RESULT);
+    JsonObject jsonObject = new JsonObject();
+    jsonObject.addProperty("jobid", jobId);
+    String post = this.mainService.post(url, jsonObject.toString());
+    return MediaUploadByUrlResult.fromJson(post);
+  }
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMeetingServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMeetingServiceImpl.java
index 3fc9d8218f..341bc97eab 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMeetingServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMeetingServiceImpl.java
@@ -11,7 +11,6 @@
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Oa.*;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMsgAuditServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMsgAuditServiceImpl.java
index 5ede317fbb..7f9b693938 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMsgAuditServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMsgAuditServiceImpl.java
@@ -66,9 +66,9 @@ public WxCpChatDatas getChatDatas(long seq, @NonNull long limit, String proxy, S
 
     List<String> libList = Arrays.asList(libFiles);
     // 判断windows系统会话存档sdk中dll的加载，因为会互相依赖所以是有顺序的，否则会导致无法加载sdk #2598
-    List<String> osLib = new LinkedList();
-    List<String> fileLib = new ArrayList();
-    libList.stream().forEach(s -> {
+    List<String> osLib = new LinkedList<>();
+    List<String> fileLib = new ArrayList<>();
+    libList.forEach(s -> {
       if (s.contains("lib")) {
         osLib.add(s);
       } else {
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java
index 2a64f52bc7..d04a051c0e 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOAuth2ServiceImpl.java
@@ -13,6 +13,8 @@
 import me.chanjar.weixin.cp.bean.workbench.WxCpSecondVerificationInfo;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
+import java.util.Optional;
+
 import static me.chanjar.weixin.common.api.WxConsts.OAuth2Scope.*;
 import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.OAuth2.*;
 
@@ -74,9 +76,9 @@ public WxCpOauth2UserInfo getUserInfo(Integer agentId, String code) throws WxErr
     JsonObject jo = GsonParser.parse(responseText);
 
     return WxCpOauth2UserInfo.builder()
-      .userId(GsonHelper.getString(jo, "UserId"))
+      .userId(Optional.ofNullable(GsonHelper.getString(jo, "UserId")).orElse(GsonHelper.getString(jo, "userid")))
       .deviceId(GsonHelper.getString(jo, "DeviceId"))
-      .openId(GsonHelper.getString(jo, "OpenId"))
+      .openId(Optional.ofNullable(GsonHelper.getString(jo, "OpenId")).orElse(GsonHelper.getString(jo, "openid")))
       .userTicket(GsonHelper.getString(jo, "user_ticket"))
       .expiresIn(GsonHelper.getString(jo, "expires_in"))
       .externalUserId(GsonHelper.getString(jo, "external_userid"))
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java
index 53aaa00ca7..59cde79a93 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImpl.java
@@ -140,7 +140,7 @@ public WxCpApprovalInfo getApprovalInfo(@NonNull Date startTime, @NonNull Date e
     if (filters != null && !filters.isEmpty()) {
       JsonArray filterJsonArray = new JsonArray();
       for (WxCpApprovalInfoQueryFilter filter : filters) {
-        filterJsonArray.add(new JsonParser().parse(filter.toJson()));
+        filterJsonArray.add(JsonParser.parseString(filter.toJson()));
       }
       jsonObject.add("filters", filterJsonArray);
     }
@@ -181,7 +181,7 @@ public WxCpApprovalInfo getApprovalInfo(@NonNull Date startTime, @NonNull Date e
     if (filters != null && !filters.isEmpty()) {
       JsonArray filterJsonArray = new JsonArray();
       for (WxCpApprovalInfoQueryFilter filter : filters) {
-        filterJsonArray.add(new JsonParser().parse(filter.toJson()));
+        filterJsonArray.add(JsonParser.parseString(filter.toJson()));
       }
       jsonObject.add("filters", filterJsonArray);
     }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaWeDriveServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaWeDriveServiceImpl.java
index 979e86e55f..a41195ae84 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaWeDriveServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpOaWeDriveServiceImpl.java
@@ -39,20 +39,18 @@ public WxCpBaseResp spaceRename(@NonNull WxCpSpaceRenameRequest request) throws
   }
 
   @Override
-  public WxCpBaseResp spaceDismiss(@NonNull String userId, @NonNull String spaceId) throws WxErrorException {
+  public WxCpBaseResp spaceDismiss(@NonNull String spaceId) throws WxErrorException {
     String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(SPACE_DISMISS);
     JsonObject jsonObject = new JsonObject();
-    jsonObject.addProperty("userid", userId);
     jsonObject.addProperty("spaceid", spaceId);
     String responseContent = this.cpService.post(apiUrl, jsonObject.toString());
     return WxCpBaseResp.fromJson(responseContent);
   }
 
   @Override
-  public WxCpSpaceInfo spaceInfo(@NonNull String userId, @NonNull String spaceId) throws WxErrorException {
+  public WxCpSpaceInfo spaceInfo(@NonNull String spaceId) throws WxErrorException {
     String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(SPACE_INFO);
     JsonObject jsonObject = new JsonObject();
-    jsonObject.addProperty("userid", userId);
     jsonObject.addProperty("spaceid", spaceId);
     String responseContent = this.cpService.post(apiUrl, jsonObject.toString());
     return WxCpSpaceInfo.fromJson(responseContent);
@@ -80,10 +78,9 @@ public WxCpBaseResp spaceSetting(@NonNull WxCpSpaceSettingRequest request) throw
   }
 
   @Override
-  public WxCpSpaceShare spaceShare(@NonNull String userId, @NonNull String spaceId) throws WxErrorException {
+  public WxCpSpaceShare spaceShare(@NonNull String spaceId) throws WxErrorException {
     String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(SPACE_SHARE);
     JsonObject jsonObject = new JsonObject();
-    jsonObject.addProperty("userid", userId);
     jsonObject.addProperty("spaceid", spaceId);
     String responseContent = this.cpService.post(apiUrl, jsonObject.toString());
     return WxCpSpaceShare.fromJson(responseContent);
@@ -114,10 +111,9 @@ public WxCpFileDownload fileDownload(@NonNull String userId, @NonNull String fil
   }
 
   @Override
-  public WxCpFileRename fileRename(@NonNull String userId, @NonNull String fileId, @NonNull String newName) throws WxErrorException {
+  public WxCpFileRename fileRename(@NonNull String fileId, @NonNull String newName) throws WxErrorException {
     String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(FILE_RENAME);
     JsonObject jsonObject = new JsonObject();
-    jsonObject.addProperty("userid", userId);
     jsonObject.addProperty("fileid", fileId);
     jsonObject.addProperty("new_name", newName);
     String responseContent = this.cpService.post(apiUrl, jsonObject.toString());
@@ -125,11 +121,10 @@ public WxCpFileRename fileRename(@NonNull String userId, @NonNull String fileId,
   }
 
   @Override
-  public WxCpFileCreate fileCreate(@NonNull String userId, @NonNull String spaceId, @NonNull String fatherId,
+  public WxCpFileCreate fileCreate(@NonNull String spaceId, @NonNull String fatherId,
                                    @NonNull Integer fileType, @NonNull String fileName) throws WxErrorException {
     String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(FILE_CREATE);
     JsonObject jsonObject = new JsonObject();
-    jsonObject.addProperty("userid", userId);
     jsonObject.addProperty("spaceid", spaceId);
     jsonObject.addProperty("fatherid", fatherId);
     jsonObject.addProperty("file_type", fileType);
@@ -146,9 +141,9 @@ public WxCpFileMove fileMove(@NonNull WxCpFileMoveRequest request) throws WxErro
   }
 
   @Override
-  public WxCpBaseResp fileDelete(@NonNull String userId, @NonNull List<String> fileId) throws WxErrorException {
+  public WxCpBaseResp fileDelete(@NonNull List<String> fileIds) throws WxErrorException {
     String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(FILE_DELETE);
-    WxCpFileDeleteRequest request = new WxCpFileDeleteRequest(userId, fileId);
+    WxCpFileDeleteRequest request = new WxCpFileDeleteRequest(fileIds);
     String responseContent = this.cpService.post(apiUrl, request.toJson());
     return WxCpBaseResp.fromJson(responseContent);
   }
@@ -168,11 +163,9 @@ public WxCpBaseResp fileAclDel(@NonNull WxCpFileAclDelRequest request) throws Wx
   }
 
   @Override
-  public WxCpBaseResp fileSetting(@NonNull String userId, @NonNull String fileId, @NonNull Integer authScope,
-                                  Integer auth) throws WxErrorException {
+  public WxCpBaseResp fileSetting(@NonNull String fileId, @NonNull Integer authScope, Integer auth) throws WxErrorException {
     String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(FILE_SETTING);
     JsonObject jsonObject = new JsonObject();
-    jsonObject.addProperty("userid", userId);
     jsonObject.addProperty("fileid", fileId);
     jsonObject.addProperty("auth_scope", authScope);
     if (auth != null) {
@@ -183,20 +176,18 @@ public WxCpBaseResp fileSetting(@NonNull String userId, @NonNull String fileId,
   }
 
   @Override
-  public WxCpFileShare fileShare(@NonNull String userId, @NonNull String fileId) throws WxErrorException {
+  public WxCpFileShare fileShare(@NonNull String fileId) throws WxErrorException {
     String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(FILE_SHARE);
     JsonObject jsonObject = new JsonObject();
-    jsonObject.addProperty("userid", userId);
     jsonObject.addProperty("fileid", fileId);
     String responseContent = this.cpService.post(apiUrl, jsonObject.toString());
     return WxCpFileShare.fromJson(responseContent);
   }
 
   @Override
-  public WxCpFileInfo fileInfo(@NonNull String userId, @NonNull String fileId) throws WxErrorException {
+  public WxCpFileInfo fileInfo(@NonNull String fileId) throws WxErrorException {
     String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(FILE_INFO);
     JsonObject jsonObject = new JsonObject();
-    jsonObject.addProperty("userid", userId);
     jsonObject.addProperty("fileid", fileId);
     String responseContent = this.cpService.post(apiUrl, jsonObject.toString());
     return WxCpFileInfo.fromJson(responseContent);
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpSchoolUserServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpSchoolUserServiceImpl.java
index fac1689e08..bdb067f923 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpSchoolUserServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpSchoolUserServiceImpl.java
@@ -16,6 +16,7 @@
 import org.apache.commons.lang3.StringUtils;
 
 import java.util.List;
+import java.util.Objects;
 
 import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.ExternalContact.*;
 import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.School.*;
@@ -98,7 +99,7 @@ public WxCpBaseResp updateStudent(@NonNull String studentUserId, String newStude
     if (StringUtils.isNotEmpty(name)) {
       jsonObject.addProperty("name", name);
     }
-    if (departments != null && departments.size() > 0) {
+    if (departments != null && !departments.isEmpty()) {
       JsonArray jsonArray = new JsonArray();
       for (Integer depart : departments) {
         jsonArray.add(new JsonPrimitive(depart));
@@ -246,7 +247,7 @@ public String convertToOpenId(@NonNull String externalUserId) throws WxErrorExce
 
   @Override
   public WxCpDepartmentList listDepartment(Integer id) throws WxErrorException {
-    String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_LIST) + id;
+    String apiUrl = Objects.isNull(id) ? this.cpService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_LIST) : String.format("%s?id=%s", this.cpService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_LIST), id);
     String responseContent = this.cpService.get(apiUrl, null);
     return WxCpDepartmentList.fromJson(responseContent);
   }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java
index 7e69152a17..1042f88d67 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceApacheHttpClientImpl.java
@@ -1,21 +1,19 @@
 package me.chanjar.weixin.cp.api.impl;
 
-
 import me.chanjar.weixin.common.bean.WxAccessToken;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.error.WxRuntimeException;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
+import me.chanjar.weixin.common.util.http.apache.ApacheBasicResponseHandler;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
 import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
 import me.chanjar.weixin.cp.config.WxCpConfigStorage;
 import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.client.BasicResponseHandler;
 import org.apache.http.impl.client.CloseableHttpClient;
 
 import java.io.IOException;
@@ -40,8 +38,8 @@ public HttpHost getRequestHttpProxy() {
   }
 
   @Override
-  public HttpType getRequestType() {
-    return HttpType.APACHE_HTTP;
+  public HttpClientType getRequestType() {
+    return HttpClientType.APACHE_HTTP;
   }
 
   @Override
@@ -61,13 +59,7 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
             .setProxy(this.httpProxy).build();
           httpGet.setConfig(config);
         }
-        String resultContent;
-        try (CloseableHttpClient httpClient = getRequestHttpClient();
-             CloseableHttpResponse response = httpClient.execute(httpGet)) {
-          resultContent = new BasicResponseHandler().handleResponse(response);
-        } finally {
-          httpGet.releaseConnection();
-        }
+        String resultContent = getRequestHttpClient().execute(httpGet, ApacheBasicResponseHandler.INSTANCE);
         WxError error = WxError.fromJson(resultContent, WxType.CP);
         if (error.getErrorCode() != 0) {
           throw new WxErrorException(error);
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceHttpComponentsImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceHttpComponentsImpl.java
new file mode 100644
index 0000000000..92fd2dbd9b
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceHttpComponentsImpl.java
@@ -0,0 +1,99 @@
+package me.chanjar.weixin.cp.api.impl;
+
+import me.chanjar.weixin.common.bean.WxAccessToken;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
+import me.chanjar.weixin.common.util.http.HttpClientType;
+import me.chanjar.weixin.common.util.http.hc.BasicResponseHandler;
+import me.chanjar.weixin.common.util.http.hc.DefaultHttpComponentsClientBuilder;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsClientBuilder;
+import me.chanjar.weixin.cp.config.WxCpConfigStorage;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
+import org.apache.hc.client5.http.classic.methods.HttpGet;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.IOException;
+
+/**
+ * The type Wx cp service apache http client.
+ *
+ * @author altusea
+ */
+public class WxCpServiceHttpComponentsImpl extends BaseWxCpServiceImpl<CloseableHttpClient, HttpHost> {
+
+  private CloseableHttpClient httpClient;
+  private HttpHost httpProxy;
+
+  @Override
+  public CloseableHttpClient getRequestHttpClient() {
+    return httpClient;
+  }
+
+  @Override
+  public HttpHost getRequestHttpProxy() {
+    return httpProxy;
+  }
+
+  @Override
+  public HttpClientType getRequestType() {
+    return HttpClientType.HTTP_COMPONENTS;
+  }
+
+  @Override
+  public String getAccessToken(boolean forceRefresh) throws WxErrorException {
+    if (!this.configStorage.isAccessTokenExpired() && !forceRefresh) {
+      return this.configStorage.getAccessToken();
+    }
+
+    synchronized (this.globalAccessTokenRefreshLock) {
+      String url = String.format(this.configStorage.getApiUrl(WxCpApiPathConsts.GET_TOKEN),
+        this.configStorage.getCorpId(), this.configStorage.getCorpSecret());
+
+      try {
+        HttpGet httpGet = new HttpGet(url);
+        if (this.httpProxy != null) {
+          RequestConfig config = RequestConfig.custom()
+            .setProxy(this.httpProxy).build();
+          httpGet.setConfig(config);
+        }
+        String resultContent = getRequestHttpClient().execute(httpGet, BasicResponseHandler.INSTANCE);
+        WxError error = WxError.fromJson(resultContent, WxType.CP);
+        if (error.getErrorCode() != 0) {
+          throw new WxErrorException(error);
+        }
+
+        WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
+        this.configStorage.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
+      } catch (IOException e) {
+        throw new WxRuntimeException(e);
+      }
+    }
+    return this.configStorage.getAccessToken();
+  }
+
+  @Override
+  public void initHttp() {
+    HttpComponentsClientBuilder apacheHttpClientBuilder = DefaultHttpComponentsClientBuilder.get();
+
+    apacheHttpClientBuilder.httpProxyHost(this.configStorage.getHttpProxyHost())
+      .httpProxyPort(this.configStorage.getHttpProxyPort())
+      .httpProxyUsername(this.configStorage.getHttpProxyUsername())
+      .httpProxyPassword(this.configStorage.getHttpProxyPassword().toCharArray());
+
+    if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) {
+      this.httpProxy = new HttpHost(this.configStorage.getHttpProxyHost(), this.configStorage.getHttpProxyPort());
+    }
+
+    this.httpClient = apacheHttpClientBuilder.build();
+  }
+
+  @Override
+  public WxCpConfigStorage getWxCpConfigStorage() {
+    return this.configStorage;
+  }
+
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java
index 661a0ed79f..f2a50db471 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceImpl.java
@@ -6,14 +6,12 @@
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.error.WxRuntimeException;
+import me.chanjar.weixin.common.util.http.apache.ApacheBasicResponseHandler;
 import me.chanjar.weixin.common.util.json.GsonParser;
 import me.chanjar.weixin.cp.config.WxCpConfigStorage;
 import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.client.BasicResponseHandler;
-import org.apache.http.impl.client.CloseableHttpClient;
 
 import java.io.IOException;
 import java.util.concurrent.locks.Lock;
@@ -55,13 +53,7 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
           RequestConfig config = RequestConfig.custom().setProxy(getRequestHttpProxy()).build();
           httpGet.setConfig(config);
         }
-        String resultContent;
-        try (CloseableHttpClient httpClient = getRequestHttpClient();
-             CloseableHttpResponse response = httpClient.execute(httpGet)) {
-          resultContent = new BasicResponseHandler().handleResponse(response);
-        } finally {
-          httpGet.releaseConnection();
-        }
+        String resultContent = getRequestHttpClient().execute(httpGet, ApacheBasicResponseHandler.INSTANCE);
         WxError error = WxError.fromJson(resultContent, WxType.CP);
         if (error.getErrorCode() != 0) {
           throw new WxErrorException(error);
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java
index ec8a3624ac..5081341851 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceJoddHttpImpl.java
@@ -9,7 +9,7 @@
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
 import me.chanjar.weixin.cp.config.WxCpConfigStorage;
 import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
 
@@ -33,8 +33,8 @@ public ProxyInfo getRequestHttpProxy() {
   }
 
   @Override
-  public HttpType getRequestType() {
-    return HttpType.JODD_HTTP;
+  public HttpClientType getRequestType() {
+    return HttpClientType.JODD_HTTP;
   }
 
   @Override
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java
index 73b933f646..af6a7e1408 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpServiceOkHttpImpl.java
@@ -5,7 +5,7 @@
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
 import me.chanjar.weixin.common.util.http.okhttp.DefaultOkHttpClientBuilder;
 import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
 import me.chanjar.weixin.cp.config.WxCpConfigStorage;
@@ -36,8 +36,8 @@ public OkHttpProxyInfo getRequestHttpProxy() {
   }
 
   @Override
-  public HttpType getRequestType() {
-    return HttpType.OK_HTTP;
+  public HttpClientType getRequestType() {
+    return HttpClientType.OK_HTTP;
   }
 
   @Override
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAgentWorkBench.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAgentWorkBench.java
index e74173ee3f..2a3e4448b6 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAgentWorkBench.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpAgentWorkBench.java
@@ -6,6 +6,7 @@
 import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 import me.chanjar.weixin.cp.bean.workbench.WorkBenchKeyData;
 import me.chanjar.weixin.cp.bean.workbench.WorkBenchList;
 import me.chanjar.weixin.cp.constant.WxCpConsts;
@@ -33,6 +34,10 @@ public class WxCpAgentWorkBench implements Serializable {
    * 用户的userid
    */
   private String userId;
+  /**
+   * 用户的userIds
+   */
+  private List<String> useridList;
   /**
    * 应用id
    */
@@ -58,6 +63,15 @@ public class WxCpAgentWorkBench implements Serializable {
    * 参考示例：<a href="wxwork://openurl?url=https%3A%2F%2Fwork.weixin.qq.com%2F">今日要闻</a>
    */
   private Boolean enableWebviewClick;
+  /**
+   * 高度。可以有两种选择：single_row与double_row。当为single_row时，高度为106px（如果隐藏标题则为147px）。
+   * 当为double_row时，高度固定为171px（如果隐藏标题则为212px）。默认值为double_row
+   */
+  private String height;
+  /**
+   * 是否要隐藏展示了应用名称的标题部分，默认值为false。
+   */
+  private Boolean hideTitle;
 
   private List<WorkBenchKeyData> keyDataList;
 
@@ -93,6 +107,20 @@ public String toUserDataString() {
     return userDataObject.toString();
   }
 
+  /**
+   * 生成批量用户数据Json字符串
+   *
+   * @return the string
+   */
+  public String toBatchUserDataString() {
+    JsonObject userDataObject = new JsonObject();
+    userDataObject.addProperty("agentid", this.agentId);
+    JsonArray useridList = WxGsonBuilder.create().toJsonTree(this.useridList).getAsJsonArray();
+    userDataObject.add("userid_list", useridList);
+    this.handleBatch(userDataObject);
+    return userDataObject.toString();
+  }
+
   /**
    * 处理不用类型的工作台数据
    */
@@ -140,9 +168,9 @@ private void handle(JsonObject templateObject) {
         webview.addProperty("url", this.url);
         webview.addProperty("jump_url", this.jumpUrl);
         webview.addProperty("pagepath", this.pagePath);
-        if (null != this.enableWebviewClick) {
-          webview.addProperty("enable_webview_click", this.enableWebviewClick);
-        }
+        webview.addProperty("enable_webview_click", this.enableWebviewClick);
+        webview.addProperty("height", this.height);
+        webview.addProperty("hide_title", this.hideTitle);
         templateObject.add("webview", webview);
         break;
       }
@@ -152,4 +180,75 @@ private void handle(JsonObject templateObject) {
     }
   }
 
+  /**
+   * 处理不用类型的工作台数据
+   */
+  private void handleBatch(JsonObject templateObject) {
+    switch (this.getType()) {
+      case WxCpConsts.WorkBenchType.KEYDATA: {
+        JsonArray keyDataArray = new JsonArray();
+        JsonObject itemsObject = new JsonObject();
+        for (WorkBenchKeyData keyDataItem : this.keyDataList) {
+          JsonObject keyDataObject = new JsonObject();
+          keyDataObject.addProperty("key", keyDataItem.getKey());
+          keyDataObject.addProperty("data", keyDataItem.getData());
+          keyDataObject.addProperty("jump_url", keyDataItem.getJumpUrl());
+          keyDataObject.addProperty("pagepath", keyDataItem.getPagePath());
+          keyDataArray.add(keyDataObject);
+        }
+        itemsObject.add("items", keyDataArray);
+        JsonObject dataObject = new JsonObject();
+        dataObject.addProperty("type", WxCpConsts.WorkBenchType.KEYDATA);
+        dataObject.add("keydata", itemsObject);
+        templateObject.add("data", dataObject);
+        break;
+      }
+      case WxCpConsts.WorkBenchType.IMAGE: {
+        JsonObject image = new JsonObject();
+        image.addProperty("url", this.url);
+        image.addProperty("jump_url", this.jumpUrl);
+        image.addProperty("pagepath", this.pagePath);
+        JsonObject dataObject = new JsonObject();
+        dataObject.addProperty("type", WxCpConsts.WorkBenchType.IMAGE);
+        dataObject.add("image", image);
+        templateObject.add("data", dataObject);
+        break;
+      }
+      case WxCpConsts.WorkBenchType.LIST: {
+        JsonArray listArray = new JsonArray();
+        JsonObject itemsObject = new JsonObject();
+        for (WorkBenchList listItem : this.lists) {
+          JsonObject listObject = new JsonObject();
+          listObject.addProperty("title", listItem.getTitle());
+          listObject.addProperty("jump_url", listItem.getJumpUrl());
+          listObject.addProperty("pagepath", listItem.getPagePath());
+          listArray.add(listObject);
+        }
+        itemsObject.add("items", listArray);
+        JsonObject dataObject = new JsonObject();
+        dataObject.addProperty("type", WxCpConsts.WorkBenchType.LIST);
+        dataObject.add("list", itemsObject);
+        templateObject.add("data", dataObject);
+        break;
+      }
+      case WxCpConsts.WorkBenchType.WEBVIEW: {
+        JsonObject webview = new JsonObject();
+        webview.addProperty("url", this.url);
+        webview.addProperty("jump_url", this.jumpUrl);
+        webview.addProperty("pagepath", this.pagePath);
+        webview.addProperty("enable_webview_click", this.enableWebviewClick);
+        webview.addProperty("height", this.height);
+        webview.addProperty("hide_title", this.hideTitle);
+        JsonObject dataObject = new JsonObject();
+        dataObject.addProperty("type", WxCpConsts.WorkBenchType.WEBVIEW);
+        dataObject.add("webview", webview);
+        templateObject.add("data", dataObject);
+        break;
+      }
+      default: {
+        //do nothing
+      }
+    }
+  }
+
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpUserInfo.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpUserInfo.java
index c6664fd0ab..9837acff36 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpUserInfo.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/WxCpTpUserInfo.java
@@ -13,31 +13,24 @@
 @Data
 @EqualsAndHashCode(callSuper = true)
 public class WxCpTpUserInfo extends WxCpBaseResp {
-
   private static final long serialVersionUID = -5028321625140879571L;
 
   /**
    * 用户所属企业的corpid
    */
-  @SerializedName("CorpId")
+  @SerializedName("corpid")
   private String corpId;
 
   /**
    * 用户在企业内的UserID，如果该企业与第三方应用有授权关系时，返回明文UserId，否则返回密文UserId
    */
-  @SerializedName("UserId")
+  @SerializedName("userid")
   private String userId;
 
-  /**
-   * 手机设备号(由企业微信在安装时随机生成，删除重装会改变，升级不受影响)
-   */
-  @SerializedName("DeviceId")
-  private String deviceId;
-
   /**
    * 成员票据，最大为512字节。
    * scope为snsapi_userinfo或snsapi_privateinfo，且用户在应用可见范围之内时返回此参数。
-   * 后续利用该参数可以获取用户信息或敏感信息，参见:https://work.weixin.qq.com/api/doc/90001/90143/91122
+   * 后续利用该参数可以获取用户信息或敏感信息，参见:<a href="https://work.weixin.qq.com/api/doc/90001/90143/91122">...</a>
    */
   @SerializedName("user_ticket")
   private String userTicket;
@@ -54,6 +47,12 @@ public class WxCpTpUserInfo extends WxCpBaseResp {
   @SerializedName("open_userid")
   private String openUserId;
 
+  /**
+   非企业成员的标识，对当前服务商唯一
+   */
+  @SerializedName("openid")
+  private String openid;
+
   /**
    * From json wx cp tp user info.
    *
@@ -64,8 +63,4 @@ public static WxCpTpUserInfo fromJson(String json) {
     return WxCpGsonBuilder.create().fromJson(json, WxCpTpUserInfo.class);
   }
 
-  public String toJson() {
-    return WxCpGsonBuilder.create().toJson(this);
-  }
-
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/corpgroup/WxCpCorpGroupCorpListAppShareInfoResp.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/corpgroup/WxCpCorpGroupCorpListAppShareInfoResp.java
index 1f02307f87..810b437e38 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/corpgroup/WxCpCorpGroupCorpListAppShareInfoResp.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/corpgroup/WxCpCorpGroupCorpListAppShareInfoResp.java
@@ -2,7 +2,6 @@
 
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import me.chanjar.weixin.cp.bean.WxCpBaseResp;
 
 import java.io.Serializable;
 import java.util.List;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpContactWayInfo.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpContactWayInfo.java
index 3a6a61902c..5da6a8fd5a 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpContactWayInfo.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpContactWayInfo.java
@@ -152,6 +152,13 @@ public static class ContactWay implements Serializable {
     @SerializedName("unionid")
     private String unionId;
 
+
+    /**
+     *非必填,是否开启同一外部企业客户只能添加同一个员工，默认为否，开启后，同一个企业的客户会优先添加到同一个跟进人
+     */
+    @SerializedName("is_exclusive")
+    private boolean isExclusive;
+
     /**
      * <pre>
      * 非必填
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpContactWayList.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpContactWayList.java
new file mode 100644
index 0000000000..04918f64e4
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpContactWayList.java
@@ -0,0 +1,63 @@
+package me.chanjar.weixin.cp.bean.external;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 「联系我」方式 列表返回对象
+ *
+ * @author <a href="https://github.com/imyzt">imyzt</a>
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@NoArgsConstructor
+public class WxCpContactWayList extends WxCpBaseResp implements Serializable {
+  private static final long serialVersionUID = -8697184659526210472L;
+
+  @SerializedName("contact_way")
+  private List<ContactWay> contactWay;
+
+  /**
+   * The type Contact way.
+   */
+  @Getter
+  @Setter
+  public static class ContactWay implements Serializable {
+    private static final long serialVersionUID = -8697184659526210472L;
+
+    /**
+     * 联系方式的配置id
+     */
+    @SerializedName("config_id")
+    private String configId;
+  }
+
+  /**
+   * From json wx cp contact way list.
+   *
+   * @param json the json
+   * @return the wx cp contact way list
+   */
+  public static WxCpContactWayList fromJson(String json) {
+    return WxCpGsonBuilder.create().fromJson(json, WxCpContactWayList.class);
+  }
+
+  /**
+   * To json string.
+   *
+   * @return the string
+   */
+  public String toJson() {
+    return WxCpGsonBuilder.create().toJson(this);
+  }
+
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/contact/WxCpExternalContactListInfo.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/contact/WxCpExternalContactListInfo.java
new file mode 100644
index 0000000000..4c0055ad80
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/contact/WxCpExternalContactListInfo.java
@@ -0,0 +1,92 @@
+package me.chanjar.weixin.cp.bean.external.contact;
+
+import com.google.gson.annotations.SerializedName;
+import java.io.Serializable;
+import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
+import me.chanjar.weixin.cp.api.WxCpService;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+/**
+ *   获取已服务的外部联系人( <a href="https://developer.work.weixin.qq.com/document/path/99434">参考文档</a>)
+ * @see WxCpService#getExternalContactService()
+ * @serial
+ */
+@Getter
+@Setter
+public class WxCpExternalContactListInfo implements Serializable {
+
+  private static final long serialVersionUID = 7114885886548364396L;
+
+  @SerializedName("next_cursor")
+  private String nextCursor;
+
+  @SerializedName("errcode")
+  private String errcode;
+
+  @SerializedName("errmsg")
+  private String errmsg;
+
+  @SerializedName("info_list")
+  private List<ExternalContactInfo> infoList;
+
+  @Getter
+  @Setter
+  public static class ExternalContactInfo implements Serializable{
+
+    private static final long serialVersionUID = -7400291089462740100L;
+
+    /**
+     * 是否被成员标记为客户
+     */
+    @SerializedName("is_customer")
+    private Boolean isCustomer;
+
+    /**
+     * 外部联系人临时ID
+     */
+    @SerializedName("tmp_openid")
+    private String tmpOpenid;
+
+    /**
+     * 外部联系人的externaluserid（如果是客户才返回）
+     */
+    @SerializedName("external_userid")
+    private String externalUserid;
+
+    /**
+     * 脱敏后的外部联系人昵称（如果是其他外部联系人才返回）
+     */
+    @SerializedName("name")
+    private String name;
+
+    /**
+     * 添加此外部联系人的企业成员或外部联系人所在群聊的群主userid
+     */
+    @SerializedName("follow_userid")
+    private String followUserid;
+
+    /**
+     * 外部联系人所在的群聊ID（如果群聊被成员标记为客户群才返回）
+     */
+    @SerializedName("chat_id")
+    private String chatId;
+
+    /**
+     * 外部联系人所在群聊的群名（如果群聊未被成员标记为客户群才返回）
+     */
+    @SerializedName("chat_name")
+    private String chatName;
+
+    /**
+     * 外部联系人首次添加/进群的时间
+     */
+    @SerializedName("add_time")
+    private Long addTime;
+  }
+  public static WxCpExternalContactListInfo fromJson(String json) {
+    return WxCpGsonBuilder.create().fromJson(json, WxCpExternalContactListInfo.class);
+  }
+
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/interceptrule/WxCpInterceptRuleInfo.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/interceptrule/WxCpInterceptRuleInfo.java
index 0e6d75bf0c..20d6b32442 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/interceptrule/WxCpInterceptRuleInfo.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/interceptrule/WxCpInterceptRuleInfo.java
@@ -4,7 +4,6 @@
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import me.chanjar.weixin.cp.bean.WxCpBaseResp;
-import me.chanjar.weixin.cp.bean.external.acquisition.WxCpCustomerAcquisitionInfo;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
 import java.io.Serializable;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/interceptrule/WxCpInterceptRuleList.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/interceptrule/WxCpInterceptRuleList.java
index 79cb9a6932..6826413e13 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/interceptrule/WxCpInterceptRuleList.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/interceptrule/WxCpInterceptRuleList.java
@@ -2,10 +2,7 @@
 
 import com.google.gson.annotations.SerializedName;
 import lombok.*;
-import me.chanjar.weixin.common.bean.ToJson;
 import me.chanjar.weixin.cp.bean.WxCpBaseResp;
-import me.chanjar.weixin.cp.bean.external.acquisition.WxCpCustomerAcquisitionInfo;
-import me.chanjar.weixin.cp.bean.external.acquisition.WxCpCustomerAcquisitionList;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 
 import java.io.Serializable;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/media/MediaUploadByUrlReq.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/media/MediaUploadByUrlReq.java
new file mode 100644
index 0000000000..c5cb21bde5
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/media/MediaUploadByUrlReq.java
@@ -0,0 +1,58 @@
+package me.chanjar.weixin.cp.bean.media;
+
+import lombok.Data;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+/**
+ * 生成异步上传任务
+ * @author <a href="https://github.com/imyzt">imyzt</a>
+ * @date 2025/04/27
+ */
+@Data
+public class MediaUploadByUrlReq {
+
+  /**
+   * 场景值。1-客户联系入群欢迎语素材（目前仅支持1）。 注意：每个场景值有对应的使用范围，详见上面的「使用场景说明」
+   */
+  private Integer scene;
+
+  /**
+   * 媒体文件类型。目前仅支持video-视频，file-普通文件 不超过32字节。
+   */
+  private String type;
+
+  /**
+   * 文件名，标识文件展示的名称。比如，使用该media_id发消息时，展示的文件名由该字段控制。 不超过128字节。
+   */
+  private String filename;
+
+  /**
+   * 文件cdn url。url要求支持Range分块下载 不超过1024字节。 如果为腾讯云cos链接，则需要设置为「公有读」权限。
+   */
+  private String url;
+
+  /**
+   * 文件md5。对比从url下载下来的文件md5是否一致。 不超过32字节。
+   */
+  private String md5;
+
+  /**
+   * From json wx cp base resp.
+   *
+   * @param json the json
+   * @return the wx cp base resp
+   */
+  public static MediaUploadByUrlReq fromJson(String json) {
+    return WxCpGsonBuilder.create().fromJson(json, MediaUploadByUrlReq.class);
+  }
+
+  /**
+   * To json string.
+   *
+   * @return the string
+   */
+  public String toJson() {
+    return WxCpGsonBuilder.create().toJson(this);
+  }
+
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/media/MediaUploadByUrlResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/media/MediaUploadByUrlResult.java
new file mode 100644
index 0000000000..cc931eed39
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/media/MediaUploadByUrlResult.java
@@ -0,0 +1,82 @@
+package me.chanjar.weixin.cp.bean.media;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import me.chanjar.weixin.cp.bean.WxCpBaseResp;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+
+import java.io.Serializable;
+
+/**
+ * 异步上传企微素材
+ * @author <a href="https://github.com/imyzt">imyzt</a>
+ * @date 2025/4/27
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class MediaUploadByUrlResult extends WxCpBaseResp implements Serializable {
+
+  private static final long serialVersionUID = 330834334738622341L;
+
+  /**
+   * 任务状态。1-处理中，2-完成，3-异常失败
+   */
+  @SerializedName("status")
+  private Integer status;
+
+  @SerializedName("detail")
+  private Detail detail;
+
+  @Data
+  public static class Detail {
+
+    /**
+     * 任务失败返回码。当status为3时返回非0，其他返回0
+     * 830001 url非法 确认url是否支持Range分块下载
+     * 830003 url下载数据失败 确认url本身是否能正常访问
+     * 45001 文件大小超过限制 确认文件在5字节~200M范围内
+     * 301019 文件MD5不匹配 确认url对应的文件内容md5，跟所填的md5参数是否一致
+     * 注意: status=2时,此处微信并未返回任何值
+     */
+    @SerializedName("errcode")
+    private Integer errCode;
+
+    /**
+     * 注意: status=2时,此处微信并未返回任何值
+     */
+    @SerializedName("errmsg")
+    private String errMsg;
+
+    /**
+     * 媒体文件上传后获取的唯一标识，3天内有效。当status为2时返回。
+     */
+    @SerializedName("media_id")
+    private String mediaId;
+
+    /**
+     * 媒体文件创建的时间戳。当status为2时返回。
+     */
+    @SerializedName("created_at")
+    private String createdAt;
+  }
+
+  /**
+   * From json wx cp media upload by url result.
+   *
+   * @param json the json
+   * @return the wx cp media upload by url result
+   */
+  public static MediaUploadByUrlResult fromJson(String json) {
+    return WxCpGsonBuilder.create().fromJson(json, MediaUploadByUrlResult.class);
+  }
+
+  /**
+   * To json string.
+   *
+   * @return the string
+   */
+  public String toJson() {
+    return WxCpGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpGroupRobotMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpGroupRobotMessage.java
index 6c889b6cec..d115245e04 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpGroupRobotMessage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpGroupRobotMessage.java
@@ -14,7 +14,6 @@
 import java.util.List;
 
 import static me.chanjar.weixin.cp.constant.WxCpConsts.GroupRobotMsgType.*;
-import static me.chanjar.weixin.cp.constant.WxCpConsts.GroupRobotMsgType.TEMPLATE_CARD;
 
 /**
  * 微信群机器人消息
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpMessageSendResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpMessageSendResult.java
index 2ddf95d8da..0883651ae6 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpMessageSendResult.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpMessageSendResult.java
@@ -50,6 +50,9 @@ public static WxCpMessageSendResult fromJson(String json) {
   @SerializedName("invalidtag")
   private String invalidTag;
 
+  @SerializedName("unlicenseduser")
+  private String unlicensedUser;
+
   @SerializedName("msgid")
   private String msgId;
 
@@ -93,4 +96,13 @@ public List<String> getInvalidPartyList() {
   public List<String> getInvalidTagList() {
     return this.content2List(this.invalidTag);
   }
+
+  /**
+   * Gets unlicensed user list.
+   *
+   * @return the unlicensed user list
+   */
+  public List<String> getUnlicensedUserList() {
+    return this.content2List(this.unlicensedUser);
+  }
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessage.java
index 8b6b0689a7..e26b152daf 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessage.java
@@ -403,7 +403,7 @@ public class WxCpTpXmlMessage implements Serializable {
    * The Agent id.
    */
   @XStreamAlias("AgentID")
-  protected String agentID;
+  protected Integer agentID;
 
   /**
    * The Pic url.
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlApprovalInfo.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlApprovalInfo.java
index 7193c7cf6f..798a5c8b00 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlApprovalInfo.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlApprovalInfo.java
@@ -118,7 +118,7 @@ public static class NotifyNode implements Serializable {
     /**
      * 抄送人userid
      */
-    @XStreamAlias("ItemUserid")
+    @XStreamAlias("ItemUserId")
     @XStreamConverter(value = XStreamCDataConverter.class)
     private String itemUserId;
 
@@ -190,7 +190,7 @@ public static class Item implements Serializable {
     /**
      * 分支审批人userid
      */
-    @XStreamAlias("ItemUserid")
+    @XStreamAlias("ItemUserId")
     @XStreamConverter(value = XStreamCDataConverter.class)
     private String itemUserId;
 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessage.java
index fb4213f504..2313bcb516 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessage.java
@@ -155,6 +155,10 @@ public class WxCpXmlMessage implements Serializable {
   @XStreamConverter(value = XStreamCDataConverter.class)
   private String memChangeCnt;
 
+  @XStreamAlias("MemChangeList")
+  @XStreamConverter(value = XStreamCDataConverter.class)
+  private String MemChangeList;
+
   @XStreamAlias("Source")
   @XStreamConverter(value = XStreamCDataConverter.class)
   private String source;
@@ -198,6 +202,13 @@ public class WxCpXmlMessage implements Serializable {
   @XStreamAlias("SelectedItems")
   private List<SelectedItem> selectedItems;
 
+  /**
+   * <a href="https://developer.work.weixin.qq.com/document/path/96488#%E5%9B%9E%E8%B0%83%E5%BC%82%E6%AD%A5%E4%BB%BB%E5%8A%A1%E7%BB%93%E6%9E%9C">异步任务id</a>
+   */
+  @XStreamAlias("JobId")
+  @XStreamConverter(value = XStreamCDataConverter.class)
+  private String jobId;
+
   /**
    * 微信客服
    * 调用拉取消息接口时，需要传此token，用于校验请求的合法性
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/BaseBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/BaseBuilder.java
index fcbc578a59..e7c2267018 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/BaseBuilder.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/BaseBuilder.java
@@ -6,10 +6,8 @@
 
 /**
  * The type Base builder.
- *
- * @param <T> the type parameter
  */
-public class BaseBuilder<T> {
+public abstract class BaseBuilder<T> {
   /**
    * The Msg type.
    */
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/TemplateCardBuilder.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/TemplateCardBuilder.java
index b174b7cc75..d3cbb89a3d 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/TemplateCardBuilder.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/messagebuilder/TemplateCardBuilder.java
@@ -427,6 +427,17 @@ public TemplateCardBuilder taskId(String taskId) {
     return this;
   }
 
+  /**
+   * Button selection template card builder.
+   *
+   * @param buttonSelection the button selection
+   * @return the template card builder
+   */
+  public TemplateCardBuilder buttonSelection(TemplateCardButtonSelection buttonSelection) {
+    this.buttonSelection = buttonSelection;
+    return this;
+  }
+
   /**
    * Buttons template card builder.
    *
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpChatModel.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpChatModel.java
index d843cad6cf..c88cb7b9be 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpChatModel.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/msgaudit/WxCpChatModel.java
@@ -25,9 +25,6 @@ public class WxCpChatModel implements Serializable {
   @SerializedName("action")
   private String action;
 
-  @SerializedName("send")
-  private String send;
-
   @SerializedName("from")
   private String from;
 
@@ -606,7 +603,7 @@ public static class File implements Serializable {
     private String sdkFileId;
 
     @SerializedName("filesize")
-    private Integer fileSize;
+    private Long fileSize;
 
     /**
      * From json file.
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinDayData.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinDayData.java
index 1a8d47c82e..c06a6d79e2 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinDayData.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinDayData.java
@@ -24,7 +24,7 @@ public class WxCpCheckinDayData implements Serializable {
    * The type Base info.
    */
   @Data
-  public class BaseInfo implements Serializable {
+  public static class BaseInfo implements Serializable {
 
 
     private static final long serialVersionUID = 3679745559788648438L;
@@ -143,7 +143,7 @@ public class CheckinTime implements Serializable {
    * The type Summary info.
    */
   @Data
-  public class SummaryInfo implements Serializable {
+  public static class SummaryInfo implements Serializable {
     private static final long serialVersionUID = 3428576099259666595L;
     /**
      * checkin_count 当日打卡次数
@@ -186,7 +186,7 @@ public class SummaryInfo implements Serializable {
    * The type Holiday infos.
    */
   @Data
-  public class HolidayInfos implements Serializable {
+  public static class HolidayInfos implements Serializable {
     private static final long serialVersionUID = -6671577072585561527L;
     /**
      * sp_number 假勤相关信息
@@ -282,7 +282,7 @@ public class Data implements Serializable {
    * The type Exception infos.
    */
   @Data
-  public class ExceptionInfos implements Serializable {
+  public static class ExceptionInfos implements Serializable {
     private static final long serialVersionUID = -5987438373762518299L;
     /**
      * exception 校准状态类型：1-迟到；2-早退；3-缺卡；4-旷工；5-地点异常；6-设备异常
@@ -313,7 +313,7 @@ public class ExceptionInfos implements Serializable {
    * The type Ot info.
    */
   @Data
-  public class OtInfo implements Serializable {
+  public static class OtInfo implements Serializable {
     private static final long serialVersionUID = -6557759801572150175L;
     /**
      * ot_status 状态：0-无加班；1-正常；2-缺时长
@@ -344,7 +344,7 @@ public class OtInfo implements Serializable {
    * The type Sp item.
    */
   @Data
-  public class SpItem implements Serializable {
+  public static class SpItem implements Serializable {
     private static final long serialVersionUID = 2423158264958352024L;
     /**
      * type 类型：1-请假；2-补卡；3-出差；4-外出；100-外勤
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinGroupBase.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinGroupBase.java
index f1c1a8580d..3bc542ccd0 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinGroupBase.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinGroupBase.java
@@ -151,6 +151,30 @@ public static class CheckinDate implements Serializable {
      */
     @SerializedName("flex_off_duty_time")
     private Integer flexOffDutyTime;
+
+    /**
+     * 是否允许弹性时间
+     */
+    @SerializedName("allow_flex")
+    private Boolean allowFlex;
+
+    /**
+     * 迟到规则
+     */
+    @SerializedName("late_rule")
+    private LateRule lateRule;
+
+    /**
+     * 最早可打卡时间限制
+     */
+    @SerializedName("max_allow_arrive_early")
+    private Integer maxAllowArriveEarly;
+
+    /**
+     * 最晚可打卡时间限制
+     */
+    @SerializedName("max_allow_arrive_late")
+    private Integer maxAllowArriveLate;
   }
 
   /**
@@ -160,6 +184,13 @@ public static class CheckinDate implements Serializable {
   public static class CheckinTime implements Serializable {
 
     private static final long serialVersionUID = -5507709858609705279L;
+
+    /**
+     * 时段id，为班次中某一堆上下班时间组合的id
+     */
+    @SerializedName("time_id")
+    private Integer timeId;
+
     /**
      * 上班时间，表示为距离当天0点的秒数。
      */
@@ -183,6 +214,60 @@ public static class CheckinTime implements Serializable {
      */
     @SerializedName("remind_off_work_sec")
     private Integer remindOffWorkSec;
+
+    /**
+     * 休息开始时间，仅单时段支持，距离0点的秒
+     */
+    @SerializedName("rest_begin_time")
+    private Integer restBeginTime;
+
+    /**
+     * 休息结束时间，仅单时段支持，距离0点的秒
+     */
+    @SerializedName("rest_end_time")
+    private Integer restEndTime;
+
+    /**
+     * 是否允许休息
+     */
+    @SerializedName("allow_rest")
+    private Boolean allowRest;
+
+    /**
+     * 最早可打卡时间，距离0点的秒数
+     */
+    @SerializedName("earliest_work_sec")
+    private Integer earliestWorkSec;
+
+    /**
+     * 最晚可打卡时间，距离0点的秒数
+     */
+    @SerializedName("latest_work_sec")
+    private Integer latestWorkSec;
+
+    /**
+     * 最早可下班打卡时间，距离0点的秒数
+     */
+    @SerializedName("earliest_off_work_sec")
+    private Integer earliestOffWorkSec;
+
+    /**
+     * 最晚可下班打卡时间，距离0点的秒数
+     */
+    @SerializedName("latest_off_work_sec")
+    private Integer latestOffWorkSec;
+
+    /**
+     * 上班无需打卡
+     */
+    @SerializedName("no_need_checkon")
+    private Boolean noNeedCheckon;
+
+    /**
+     * 下班无需打卡
+     */
+    @SerializedName("no_need_checkoff")
+    private Boolean noNeedCheckoff;
   }
 
   /**
@@ -438,6 +523,17 @@ public static class LateRule implements Serializable {
 
     private static final long serialVersionUID = 5604969713950037053L;
 
+    /**
+     * 晚走的时间 距离最晚一个下班的时间单位：秒
+     */
+    @SerializedName("offwork_after_time")
+    private Integer offWorkAfterTime;
+
+    /**
+     * 第二天第一个班次允许迟到的弹性时间单位：秒
+     */
+    @SerializedName("onwork_flex_time")
+    private Integer onWorkFlexTime;
 
     /**
      * 是否允许超时下班（下班晚走次日晚到）允许时onwork_flex_time，offwork_after_time才有意义
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinSchedule.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinSchedule.java
index af310439fc..1e8797cf7e 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinSchedule.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCheckinSchedule.java
@@ -49,7 +49,7 @@ public class WxCpCheckinSchedule implements Serializable {
    * The type User schedule.
    */
   @Data
-  public class UserSchedule implements Serializable {
+  public static class UserSchedule implements Serializable {
     private static final long serialVersionUID = 9138985222324576857L;
     /**
      * scheduleList 个人排班表信息
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCropCheckinOption.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCropCheckinOption.java
index bda77447fe..8cdccd9953 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCropCheckinOption.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpCropCheckinOption.java
@@ -53,6 +53,12 @@ public class WxCpCropCheckinOption extends WxCpCheckinGroupBase implements Seria
   @SerializedName("ot_info")
   private OtInfo otInfo;
 
+  /**
+   * 加班信息V2，新版API返回的加班信息结构
+   */
+  @SerializedName("ot_info_v2")
+  private OtInfoV2 otInfoV2;
+
   /**
    * 每月最多补卡次数，默认-1表示不限制
    */
@@ -418,4 +424,94 @@ public static class OtApplyInfo implements Serializable {
     private Integer otNonworkingDaySpanDayTime;
 
   }
+
+  /**
+   * 加班信息V2，新版API返回的加班信息结构
+   */
+  @Data
+  public static class OtInfoV2 implements Serializable {
+
+    private static final long serialVersionUID = 1610150484871066200L;
+
+    /**
+     * 工作日加班配置
+     */
+    @SerializedName("workdayconf")
+    private WorkdayConf workdayConf;
+
+    /**
+     * 非工作日加班配置
+     */
+    @SerializedName("restdayconf")
+    private RestdayConf restdayConf;
+
+    /**
+     * 节假日加班配置
+     */
+    @SerializedName("holidayconf")
+    private HolidayConf holidayConf;
+
+    /**
+     * 工作日加班配置
+     */
+    @Data
+    public static class WorkdayConf implements Serializable {
+      private static final long serialVersionUID = 1610150484871066201L;
+
+      /**
+       * 是否允许工作日加班，true为允许，false为不允许
+       */
+      @SerializedName("allow_ot")
+      private Boolean allowOt;
+
+      /**
+       * 加班类型
+       * 0：以加班申请核算打卡记录（根据打卡记录和加班申请核算）,
+       * 1：以打卡时间为准（根据打卡时间计算），
+       * 2: 以加班申请审批为准（只根据加班申请计算）
+       */
+      @SerializedName("type")
+      private Integer type;
+    }
+
+    /**
+     * 非工作日加班配置
+     */
+    @Data
+    public static class RestdayConf implements Serializable {
+      private static final long serialVersionUID = 1610150484871066202L;
+
+      /**
+       * 是否允许非工作日加班，true为允许，false为不允许
+       */
+      @SerializedName("allow_ot")
+      private Boolean allowOt;
+
+      /**
+       * 加班类型
+       */
+      @SerializedName("type")
+      private Integer type;
+    }
+
+    /**
+     * 节假日加班配置
+     */
+    @Data
+    public static class HolidayConf implements Serializable {
+      private static final long serialVersionUID = 1610150484871066203L;
+
+      /**
+       * 是否允许节假日加班，true为允许，false为不允许
+       */
+      @SerializedName("allow_ot")
+      private Boolean allowOt;
+
+      /**
+       * 加班类型
+       */
+      @SerializedName("type")
+      private Integer type;
+    }
+  }
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApprovalTemplateResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApprovalTemplateResult.java
index 2a497d15fc..b926539008 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApprovalTemplateResult.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApprovalTemplateResult.java
@@ -6,6 +6,7 @@
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.experimental.Accessors;
+import me.chanjar.weixin.cp.bean.oa.templatedata.TemplateTips;
 import me.chanjar.weixin.cp.bean.oa.templatedata.TemplateTitle;
 import me.chanjar.weixin.cp.bean.oa.templatedata.control.*;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
@@ -16,7 +17,7 @@
 /**
  * 审批模板详情
  *
- * @author gyv12345 @163.com / Wang_Wong
+ * @author gyv12345@163.com / Wang_Wong
  */
 @Data
 @Builder
@@ -94,6 +95,9 @@ public static class TemplateConfig implements Serializable {
     @SerializedName("vacation_list")
     private TemplateVacation vacationList;
 
+    @SerializedName("tips")
+    private TemplateTips tips;
+
   }
 
   @Data
@@ -117,7 +121,7 @@ public static class TemplateOption implements Serializable {
 
     /**
      * 获取审批模板详情，value为list类型
-     * https://developer.work.weixin.qq.com/document/path/91982
+     * <a href="https://developer.work.weixin.qq.com/document/path/91982">文档链接</a>
      */
     @SerializedName("value")
     private List<TemplateTitle> value;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/applydata/ContentValue.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/applydata/ContentValue.java
index 158206867e..92ec8a43e8 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/applydata/ContentValue.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/applydata/ContentValue.java
@@ -34,6 +34,9 @@ public class ContentValue implements Serializable {
 
   private List<ContentValue.Department> departments;
 
+  @SerializedName("new_tips")
+  private NewTips newTips;
+
   private List<ContentValue.File> files;
 
   private List<ContentValue.Child> children;
@@ -114,6 +117,68 @@ public static class Department implements Serializable {
     private String name;
   }
 
+  /**
+   * The type Tips.
+   */
+  @Data
+  public static class NewTips implements Serializable {
+    private static final long serialVersionUID = 1094978100200056100L;
+    @SerializedName("tips_content")
+    private List<TipsContent> tipsContent;
+
+    /**
+     * The type tips_content.
+     */
+    @Data
+    public static class TipsContent implements Serializable {
+      private static final long serialVersionUID = 559432801311084797L;
+      @SerializedName("text")
+      private Text text;
+      private String lang;
+
+      /**
+       * The type sub_text.
+       */
+      @Data
+      public static class Text implements Serializable {
+        private static final long serialVersionUID = -70174360931158924L;
+        @SerializedName("sub_text")
+        private List<SubText> subText;
+      }
+
+      /**
+       * The type sub_text.
+       */
+      @Data
+      public static class SubText implements Serializable {
+        private static final long serialVersionUID = -8226911175438019317L;
+        private Integer type;
+        private Content content;
+
+        @Data
+        public static class Content implements Serializable {
+          private static final long serialVersionUID = -6813250009451940525L;
+          @SerializedName("plain_text")
+          private PlainText plainText;
+          private Link link;
+
+          @Data
+          public static class PlainText implements Serializable {
+            private static final long serialVersionUID = -599377674188314118L;
+            private String content;
+          }
+
+          @Data
+          public static class Link implements Serializable {
+            private static final long serialVersionUID = 2784173996170990308L;
+            private String title;
+            private String url;
+          }
+        }
+      }
+    }
+  }
+
   /**
    * The type File.
    */
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeeting.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeeting.java
index 0efbc5a772..0ad79538e4 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeeting.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeeting.java
@@ -65,6 +65,35 @@ public class WxCpMeeting implements Serializable, ToJson {
   @SerializedName("agentid")
   private Integer agentId;
 
+  /**
+   * 发起人所在部门
+   */
+  @SerializedName("main_department")
+  private Integer mainDepartment;
+
+  /**
+   * 会议的状态。
+   * 1：待开始
+   * 2：会议中
+   * 3：已结束
+   * 4：已取消
+   * 5：已过期
+   */
+  @SerializedName("status")
+  public Integer status;
+
+  /**
+   * 会议类型。
+   * 0：一次性会议
+   * 1：周期性会议
+   * 2：微信专属会议
+   * 3：Rooms 投屏会议
+   * 5：个人会议号会议
+   * 6：网络研讨会
+   */
+  @SerializedName("meeting_type")
+  private Integer meetingType;
+
 
   /**
    * 参与会议的成员。会议人数上限，以指定的「管理员」可预约的人数上限来校验，普通企业与会人员最多100；
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeetingUpdateResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeetingUpdateResult.java
index dfd200f2a8..21b8e88817 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeetingUpdateResult.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/meeting/WxCpMeetingUpdateResult.java
@@ -1,15 +1,11 @@
 package me.chanjar.weixin.cp.bean.oa.meeting;
 
-import com.google.common.base.Splitter;
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
 import me.chanjar.weixin.cp.bean.WxCpBaseResp;
 import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
-import org.apache.commons.lang3.StringUtils;
 
 import java.io.Serializable;
-import java.util.Collections;
-import java.util.List;
 
 /**
  * 为标签添加或移除用户结果对象类.
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateConfig.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateConfig.java
index 1a00baad0f..91ee8b7cde 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateConfig.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateConfig.java
@@ -37,4 +37,6 @@ public class TemplateConfig implements Serializable {
   @SerializedName("vacation_list")
   private TemplateVacation vacationList;
 
+  private TemplateTips tips;
+
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateOptions.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateOptions.java
index 32ada7b338..8b1605a5a1 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateOptions.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateOptions.java
@@ -3,6 +3,7 @@
 import lombok.Data;
 
 import java.io.Serializable;
+import java.util.List;
 
 /**
  * The type Template options.
@@ -17,11 +18,8 @@ public class TemplateOptions implements Serializable {
   private String key;
 
   /**
-   * 创建审批模板，value为对象类型
-   * https://developer.work.weixin.qq.com/document/path/97437#%E9%99%845-%E5%8D%95%E9%80%89%E5%A4%9A%E9%80%89%E6%8E%A7%E4%BB%B6%EF%BC%88control%E5%8F%82%E6%95%B0%E4%B8%BAselector%EF%BC%89
-   *
-   * 获取审批模板详情，value为list类型
-   * https://developer.work.weixin.qq.com/document/path/91982
+   * <a href="https://developer.work.weixin.qq.com/document/path/97437#%E9%99%845-%E5%8D%95%E9%80%89%E5%A4%9A%E9%80%89%E6%8E%A7%E4%BB%B6%EF%BC%88control%E5%8F%82%E6%95%B0%E4%B8%BAselector%EF%BC%89">创建审批模板，value为对象类型</a>
+   * <a href="https://developer.work.weixin.qq.com/document/path/91982">获取审批模板详情，value为list类型</a>
    **/
-  private TemplateTitle value;
+  private List<TemplateTitle> value;
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTips.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTips.java
new file mode 100644
index 0000000000..58daeb007c
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTips.java
@@ -0,0 +1,18 @@
+package me.chanjar.weixin.cp.bean.oa.templatedata;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author mrsiu@msn.com
+ * @version 1.0
+ * @date 2025/1/16 09:40
+ */
+@Data
+public class TemplateTips {
+
+  @SerializedName("tips_content")
+  private List<TemplateTipsContent> tipsContent;
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsContent.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsContent.java
new file mode 100644
index 0000000000..939e6819a0
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsContent.java
@@ -0,0 +1,15 @@
+package me.chanjar.weixin.cp.bean.oa.templatedata;
+
+import lombok.Data;
+
+/**
+ * @author mrsiu@msn.com
+ * @version 1.0
+ * @date 2025/1/16 09:42
+ */
+@Data
+public class TemplateTipsContent {
+
+  private TemplateTipsText text;
+  private String lang;
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubText.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubText.java
new file mode 100644
index 0000000000..ac4681038c
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubText.java
@@ -0,0 +1,14 @@
+package me.chanjar.weixin.cp.bean.oa.templatedata;
+
+import lombok.Data;
+
+/**
+ * @author mrsiu@msn.com
+ * @version 1.0
+ * @date 2025/1/16 09:45
+ */
+@Data
+public class TemplateTipsSubText {
+  private Integer type;
+  private TemplateTipsSubTextContent content;
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubTextContent.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubTextContent.java
new file mode 100644
index 0000000000..9c99b2688e
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubTextContent.java
@@ -0,0 +1,16 @@
+package me.chanjar.weixin.cp.bean.oa.templatedata;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+
+/**
+ * @author mrsiu@msn.com
+ * @version 1.0
+ * @date 2025/1/16 09:46
+ */
+@Data
+public class TemplateTipsSubTextContent {
+  @SerializedName("plain_text")
+  private TemplateTipsSubTextContentPlainText plainText;
+  private TemplateTipsSubTextContentLink link;
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubTextContentLink.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubTextContentLink.java
new file mode 100644
index 0000000000..4cd198409a
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubTextContentLink.java
@@ -0,0 +1,14 @@
+package me.chanjar.weixin.cp.bean.oa.templatedata;
+
+import lombok.Data;
+
+/**
+ * @author mrsiu@msn.com
+ * @version 1.0
+ * @date 2025/1/16 09:49
+ */
+@Data
+public class TemplateTipsSubTextContentLink {
+  private String title;
+  private String url;
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubTextContentPlainText.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubTextContentPlainText.java
new file mode 100644
index 0000000000..12969cdcdb
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsSubTextContentPlainText.java
@@ -0,0 +1,13 @@
+package me.chanjar.weixin.cp.bean.oa.templatedata;
+
+import lombok.Data;
+
+/**
+ * @author  mrsiu@msn.com
+ * @date  2025/1/16 09:47
+ * @version  1.0
+ */
+@Data
+public class TemplateTipsSubTextContentPlainText {
+     private String content;
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsText.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsText.java
new file mode 100644
index 0000000000..100c5bb137
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/templatedata/TemplateTipsText.java
@@ -0,0 +1,17 @@
+package me.chanjar.weixin.cp.bean.oa.templatedata;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author  mrsiu@msn.com
+ * @date  2025/1/16 09:43
+ * @version  1.0
+ */
+@Data
+public class TemplateTipsText {
+    @SerializedName("sub_text")
+    private List<TemplateTipsSubText> subText;
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/wedrive/WxCpFileDeleteRequest.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/wedrive/WxCpFileDeleteRequest.java
index bb740f3935..3b95629cc6 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/wedrive/WxCpFileDeleteRequest.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/wedrive/WxCpFileDeleteRequest.java
@@ -22,9 +22,6 @@
 public class WxCpFileDeleteRequest implements Serializable {
   private static final long serialVersionUID = -4960239393895754138L;
 
-  @SerializedName("userid")
-  private String userId;
-
   @SerializedName("fileid")
   private List<String> fileId;
 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/wedrive/WxCpFileDownload.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/wedrive/WxCpFileDownload.java
index 9c2507c681..f52f0ca424 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/wedrive/WxCpFileDownload.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/wedrive/WxCpFileDownload.java
@@ -35,8 +35,4 @@ public static WxCpFileDownload fromJson(String json) {
     return WxCpGsonBuilder.create().fromJson(json, WxCpFileDownload.class);
   }
 
-  public String toJson() {
-    return WxCpGsonBuilder.create().toJson(this);
-  }
-
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/wedrive/WxCpFileListRequest.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/wedrive/WxCpFileListRequest.java
index 1855c1a0da..890f35d364 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/wedrive/WxCpFileListRequest.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/wedrive/WxCpFileListRequest.java
@@ -21,9 +21,6 @@
 public class WxCpFileListRequest implements Serializable {
   private static final long serialVersionUID = -4960239393895754138L;
 
-  @SerializedName("userid")
-  private String userId;
-
   @SerializedName("spaceid")
   private String spaceId;
 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/wedrive/WxCpFileMoveRequest.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/wedrive/WxCpFileMoveRequest.java
index 5802e3c276..58460067bc 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/wedrive/WxCpFileMoveRequest.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/wedrive/WxCpFileMoveRequest.java
@@ -21,12 +21,6 @@
 public class WxCpFileMoveRequest implements Serializable {
   private static final long serialVersionUID = -4960239393895754138L;
 
-  /**
-   * 操作者userid
-   */
-  @SerializedName("userid")
-  private String userId;
-
   /**
    * 如果移动到的目标目录与需要移动的文件重名时，是否覆盖。
    * true:重名文件覆盖
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/wedrive/WxCpFileUploadRequest.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/wedrive/WxCpFileUploadRequest.java
index 7a107562bb..d6ffe7b11c 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/wedrive/WxCpFileUploadRequest.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/oa/wedrive/WxCpFileUploadRequest.java
@@ -21,9 +21,6 @@
 public class WxCpFileUploadRequest implements Serializable {
   private static final long serialVersionUID = -4960239393895754138L;
 
-  @SerializedName("userid")
-  private String userId;
-
   @SerializedName("spaceid")
   private String spaceId;
 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/templatecard/MultipleSelect.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/templatecard/MultipleSelect.java
index c9f15e6d74..1a078bea46 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/templatecard/MultipleSelect.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/templatecard/MultipleSelect.java
@@ -59,7 +59,7 @@ public JsonObject toJson() {
     }
 // select_list
     List<CheckboxOption> options = this.getOptions();
-    if (null != options && options.size() > 0) {
+    if (null != options && !options.isEmpty()) {
       JsonArray optionJsonArray = new JsonArray();
       for (CheckboxOption option : this.getOptions()) {
         JsonObject tempObject = option.toJson();
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/templatecard/TemplateCardButtonSelection.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/templatecard/TemplateCardButtonSelection.java
index f279eb2274..b74346a938 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/templatecard/TemplateCardButtonSelection.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/templatecard/TemplateCardButtonSelection.java
@@ -44,7 +44,7 @@ public JsonObject toJson() {
       btnObject.addProperty("selected_id", this.selectedId);
     }
 
-    if (this.optionList != null && this.optionList.size() > 0) {
+    if (this.optionList != null && !this.optionList.isEmpty()) {
       JsonArray optionJsonArray = new JsonArray();
       for (TemplateCardButtonSelectionOption jump : this.getOptionList()) {
         JsonObject tempObject = jump.toJson();
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java
index 72f143fc37..b4316e7e85 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/WxCpTpConfigStorage.java
@@ -146,6 +146,13 @@ public interface WxCpTpConfigStorage {
    */
   String getCorpSecret();
 
+  /**
+   * Sets provider secret.
+   *
+   * @param providerSecret the provider secret
+   */
+  void setProviderSecret(String providerSecret);
+
   /**
    * 服务商secret
    *
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/AbstractWxCpInRedisConfigImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/AbstractWxCpInRedisConfigImpl.java
index 780e722c30..a078e8cf9e 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/AbstractWxCpInRedisConfigImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/AbstractWxCpInRedisConfigImpl.java
@@ -180,4 +180,17 @@ public boolean isAgentJsapiTicketExpired() {
     Long expire = redisOps.getExpire(this.agentJsapiTicketKey);
     return expire == null || expire < 2;
   }
+
+  @Override
+  public String toString() {
+    return "AbstractWxCpInRedisConfigImpl{" +
+      "corpId='" + getCorpId() + '\'' +
+      ", agentId=" + getAgentId() +
+      ", keyPrefix='" + keyPrefix + '\'' +
+      ", accessTokenKey='" + accessTokenKey + '\'' +
+      ", jsapiTicketKey='" + jsapiTicketKey + '\'' +
+      ", agentJsapiTicketKey='" + agentJsapiTicketKey + '\'' +
+      ", lockKey='" + lockKey + '\'' +
+      '}';
+  }
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpCorpGroupDefaultConfigImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpCorpGroupDefaultConfigImpl.java
index bef838c90d..b3d4834426 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpCorpGroupDefaultConfigImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpCorpGroupDefaultConfigImpl.java
@@ -18,6 +18,8 @@
  * @author libo
  */
 public class WxCpCorpGroupDefaultConfigImpl implements WxCpCorpGroupConfigStorage, Serializable {
+  private static final long serialVersionUID = -8392908346536154435L;
+
   private final transient Map<String, Lock> corpAccessTokenLocker = new ConcurrentHashMap<>();
 
   private final Map<String, String> corpAccessTokenMap = new HashMap<>();
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpCorpGroupRedissonConfigImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpCorpGroupRedissonConfigImpl.java
index 8146b580d0..1ef05ba8b3 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpCorpGroupRedissonConfigImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpCorpGroupRedissonConfigImpl.java
@@ -23,6 +23,8 @@
  */
 @Builder
 public class WxCpCorpGroupRedissonConfigImpl implements WxCpCorpGroupConfigStorage, Serializable {
+  private static final long serialVersionUID = 1269450173683931930L;
+
   private final transient Map<String, Lock> corpAccessTokenLocker = new ConcurrentHashMap<>();
 
   /**
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpDefaultConfigImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpDefaultConfigImpl.java
index a4b8af4677..5d08825910 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpDefaultConfigImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpDefaultConfigImpl.java
@@ -269,6 +269,11 @@ public void setCorpSecret(String corpSecret) {
     this.corpSecret = corpSecret;
   }
 
+  @Override
+  public void setProviderSecret(String providerSecret) {
+    this.providerSecret = providerSecret;
+  }
+
   @Override
   public String getProviderSecret() {
     return providerSecret;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpRedissonConfigImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpRedissonConfigImpl.java
index 02193cfd33..d483bfd53f 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpRedissonConfigImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/config/impl/WxCpTpRedissonConfigImpl.java
@@ -212,6 +212,11 @@ public String getCorpSecret() {
     return corpSecret;
   }
 
+  @Override
+  public void setProviderSecret(String providerSecret) {
+    this.providerSecret = providerSecret;
+  }
+
   @Override
   public String getProviderSecret() {
     return providerSecret;
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
index d90bda6ccc..093d386e6a 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java
@@ -130,6 +130,10 @@ interface WorkBench {
      * The constant WORKBENCH_DATA_SET.
      */
     String WORKBENCH_DATA_SET = "/cgi-bin/agent/set_workbench_data";
+    /**
+     * The constant WORKBENCH_BATCH_DATA_SET.
+     */
+    String WORKBENCH_BATCH_DATA_SET = "/cgi-bin/agent/batch_set_workbench_data";
   }
 
   /**
@@ -234,6 +238,12 @@ interface Media {
      * The constant JSSDK_MEDIA_GET.
      */
     String JSSDK_MEDIA_GET = "/cgi-bin/media/get/jssdk";
+
+    /** The constant GET_UPLOAD_BY_URL_RESULT. */
+    String GET_UPLOAD_BY_URL_RESULT = "/cgi-bin/media/get_upload_by_url_result";
+
+    /** The constant UPLOAD_BY_URL. */
+    String UPLOAD_BY_URL = "/cgi-bin/media/upload_by_url";
   }
 
   /**
@@ -691,7 +701,7 @@ interface School {
     /**
      * The constant DEPARTMENT_LIST.
      */
-    String DEPARTMENT_LIST = "/cgi-bin/school/department/list?id=";
+    String DEPARTMENT_LIST = "/cgi-bin/school/department/list";
 
     /**
      * The constant GET_PAYMENT_RESULT.
@@ -1085,6 +1095,10 @@ interface ExternalContact {
      * The constant GET_CONTACT_WAY.
      */
     String GET_CONTACT_WAY = "/cgi-bin/externalcontact/get_contact_way";
+    /**
+     * The constant LIST_CONTACT_WAY.
+     */
+    String LIST_CONTACT_WAY = "/cgi-bin/externalcontact/list_contact_way";
     /**
      * The constant UPDATE_CONTACT_WAY.
      */
@@ -1137,6 +1151,9 @@ interface ExternalContact {
      * The constant GET_CONTACT_DETAIL_BATCH.
      */
     String GET_CONTACT_DETAIL_BATCH = "/cgi-bin/externalcontact/batch/get_by_user?";
+
+    String GET_CONTACT_LIST = "/cgi-bin/externalcontact/contact_list?";
+
     /**
      * The constant UPDATE_REMARK.
      */
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java
index 606dcea6d2..3d51c9e2c9 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpConsts.java
@@ -219,6 +219,11 @@ public static class EventType {
      */
     public static final String CUSTOMER_ACQUISITION = "customer_acquisition";
 
+    /**
+     * <a href="https://developer.work.weixin.qq.com/document/path/96488#%E5%9B%9E%E8%B0%83%E5%BC%82%E6%AD%A5%E4%BB%BB%E5%8A%A1%E7%BB%93%E6%9E%9C">异步上传临时素材结果回调通知</a>
+     */
+    public static final String UPLOAD_MEDIA_JOB_FINISH = "upload_media_job_finish";
+
   }
 
   /**
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/BaseWxCpCgServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/BaseWxCpCgServiceImpl.java
index 5fb56cc157..9991073739 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/BaseWxCpCgServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/BaseWxCpCgServiceImpl.java
@@ -17,7 +17,6 @@
 import me.chanjar.weixin.cp.bean.corpgroup.WxCpCorpGroupCorpGetTokenReq;
 import me.chanjar.weixin.cp.bean.corpgroup.WxCpMaTransferSession;
 import me.chanjar.weixin.cp.config.WxCpCorpGroupConfigStorage;
-import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
 import me.chanjar.weixin.cp.corpgroup.service.WxCpCgService;
 import me.chanjar.weixin.cp.corpgroup.service.WxCpLinkedCorpService;
 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/WxCpCgServiceApacheHttpClientImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/WxCpCgServiceApacheHttpClientImpl.java
index fde2c76bb2..13349c3d80 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/WxCpCgServiceApacheHttpClientImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/WxCpCgServiceApacheHttpClientImpl.java
@@ -1,6 +1,6 @@
 package me.chanjar.weixin.cp.corpgroup.service.impl;
 
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
 import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
 import org.apache.http.HttpHost;
@@ -25,8 +25,8 @@ public HttpHost getRequestHttpProxy() {
   }
 
   @Override
-  public HttpType getRequestType() {
-    return HttpType.APACHE_HTTP;
+  public HttpClientType getRequestType() {
+    return HttpClientType.APACHE_HTTP;
   }
 
   @Override
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/WxCpCgServiceHttpComponentsImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/WxCpCgServiceHttpComponentsImpl.java
new file mode 100644
index 0000000000..d5c60ad037
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/corpgroup/service/impl/WxCpCgServiceHttpComponentsImpl.java
@@ -0,0 +1,47 @@
+package me.chanjar.weixin.cp.corpgroup.service.impl;
+
+import me.chanjar.weixin.common.util.http.HttpClientType;
+import me.chanjar.weixin.common.util.http.hc.DefaultHttpComponentsClientBuilder;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsClientBuilder;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpHost;
+
+/**
+ * @author altusea
+ */
+public class WxCpCgServiceHttpComponentsImpl extends BaseWxCpCgServiceImpl<CloseableHttpClient, HttpHost> {
+  private CloseableHttpClient httpClient;
+  private HttpHost httpProxy;
+
+  @Override
+  public CloseableHttpClient getRequestHttpClient() {
+    return httpClient;
+  }
+
+  @Override
+  public HttpHost getRequestHttpProxy() {
+    return httpProxy;
+  }
+
+  @Override
+  public HttpClientType getRequestType() {
+    return HttpClientType.HTTP_COMPONENTS;
+  }
+
+  @Override
+  public void initHttp() {
+    HttpComponentsClientBuilder apacheHttpClientBuilder = DefaultHttpComponentsClientBuilder.get();
+
+    apacheHttpClientBuilder.httpProxyHost(this.configStorage.getHttpProxyHost())
+      .httpProxyPort(this.configStorage.getHttpProxyPort())
+      .httpProxyUsername(this.configStorage.getHttpProxyUsername())
+      .httpProxyPassword(this.configStorage.getHttpProxyPassword().toCharArray());
+
+    if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) {
+      this.httpProxy = new HttpHost(this.configStorage.getHttpProxyHost(), this.configStorage.getHttpProxyPort());
+    }
+
+    this.httpClient = apacheHttpClientBuilder.build();
+  }
+
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java
index e2daeab546..94f0838a9d 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/message/WxCpMessageRouter.java
@@ -205,12 +205,12 @@ public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage, final Map<String,
       }
     }
 
-    if (matchRules.size() == 0) {
+    if (matchRules.isEmpty()) {
       return null;
     }
 
     WxCpXmlOutMessage res = null;
-    final List<Future> futures = new ArrayList<>();
+    final List<Future<?>> futures = new ArrayList<>();
     for (final WxCpMessageRouterRule rule : matchRules) {
       // 返回最后一个非异步的rule的执行结果
       if (rule.isAsync()) {
@@ -228,9 +228,9 @@ public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage, final Map<String,
       }
     }
 
-    if (futures.size() > 0) {
+    if (!futures.isEmpty()) {
       this.executorService.submit(() -> {
-        for (Future future : futures) {
+        for (Future<?> future : futures) {
           try {
             future.get();
             log.debug("End session access: async=true, sessionId={}", wxMessage.getFromUserName());
@@ -258,7 +258,7 @@ public WxCpXmlOutMessage route(final WxCpXmlMessage wxMessage) {
     return this.route(wxMessage, new HashMap<>(2));
   }
 
-  private boolean isMsgDuplicated(WxCpXmlMessage wxMessage) {
+  protected boolean isMsgDuplicated(WxCpXmlMessage wxMessage) {
     StringBuilder messageId = new StringBuilder();
     if (wxMessage.getMsgId() == null) {
       messageId.append(wxMessage.getCreateTime())
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageRouter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageRouter.java
index 1df52149c8..564be38692 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageRouter.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/message/WxCpTpMessageRouter.java
@@ -213,12 +213,12 @@ public WxCpXmlOutMessage route(final String suiteId, final WxCpTpXmlMessage wxMe
       }
     }
 
-    if (matchRules.size() == 0) {
+    if (matchRules.isEmpty()) {
       return null;
     }
 
     WxCpXmlOutMessage res = null;
-    final List<Future> futures = new ArrayList<>();
+    final List<Future<?>> futures = new ArrayList<>();
     for (final WxCpTpMessageRouterRule rule : matchRules) {
       // 返回最后一个非异步的rule的执行结果
       if (rule.isAsync()) {
@@ -236,9 +236,9 @@ public WxCpXmlOutMessage route(final String suiteId, final WxCpTpXmlMessage wxMe
       }
     }
 
-    if (futures.size() > 0) {
+    if (!futures.isEmpty()) {
       this.executorService.submit(() -> {
-        for (Future future : futures) {
+        for (Future<?> future : futures) {
           try {
             future.get();
             log.debug("End session access: async=true, sessionId={}", wxMessage.getSuiteId());
@@ -278,7 +278,7 @@ public WxCpXmlOutMessage route(final WxCpTpXmlMessage wxMessage) {
     return this.route(wxMessage, new HashMap<>(2));
   }
 
-  private boolean isMsgDuplicated(final String suiteId, WxCpTpXmlMessage wxMessage) {
+  protected boolean isMsgDuplicated(final String suiteId, WxCpTpXmlMessage wxMessage) {
     StringBuilder messageId = new StringBuilder();
     messageId.append(wxMessage.getToUserName());
     if (wxMessage.getInfoType() != null) {
@@ -306,7 +306,8 @@ private boolean isMsgDuplicated(final String suiteId, WxCpTpXmlMessage wxMessage
           .append("-").append(wxMessage.getCreateTime())
           .append("-").append(wxMessage.getFromUserName())
           .append("-").append(StringUtils.trimToEmpty(wxMessage.getEvent()))
-          .append("-").append(StringUtils.trimToEmpty(wxMessage.getEventKey()));
+          .append("-").append(StringUtils.trimToEmpty(wxMessage.getEventKey()))
+          .append("-").append(StringUtils.trimToEmpty(wxMessage.getExternalUserID()));
       }
     }
 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpDepartmentService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpDepartmentService.java
index 8cbd17d6de..706add84aa 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpDepartmentService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpDepartmentService.java
@@ -17,7 +17,7 @@ public interface WxCpTpDepartmentService {
    * <pre>
    * 部门管理接口 - 创建部门.
    * 最多支持创建500个部门
-   * 详情请见: https://work.weixin.qq.com/api/doc#90000/90135/90205
+   * 详情请见: <a href="https://work.weixin.qq.com/api/doc#90000/90135/90205">...</a>
    * </pre>
    *
    * @param depart 部门
@@ -29,7 +29,7 @@ public interface WxCpTpDepartmentService {
   /**
    * <pre>
    * 部门管理接口 - 获取部门列表.
-   * 详情请见: https://work.weixin.qq.com/api/doc#90000/90135/90208
+   * 详情请见: <a href="https://work.weixin.qq.com/api/doc#90000/90135/90208">...</a>
    * </pre>
    *
    * @param id     部门id。获取指定部门及其下的子部门。非必需，可为null
@@ -42,7 +42,7 @@ public interface WxCpTpDepartmentService {
   /**
    * <pre>
    * 部门管理接口 - 更新部门.
-   * 详情请见: https://work.weixin.qq.com/api/doc#90000/90135/90206
+   * 详情请见: <a href="https://work.weixin.qq.com/api/doc#90000/90135/90206">...</a>
    * 如果id为0(未部门),1(黑名单),2(星标组)，或者不存在的id，微信会返回系统繁忙的错误
    * </pre>
    *
@@ -54,7 +54,7 @@ public interface WxCpTpDepartmentService {
   /**
    * <pre>
    * 部门管理接口 - 删除部门.
-   * 详情请见: https://work.weixin.qq.com/api/doc#90000/90135/90207
+   * 详情请见: <a href="https://work.weixin.qq.com/api/doc#90000/90135/90207">...</a>
    * 应用须拥有指定部门的管理权限
    * </pre>
    *
@@ -66,7 +66,7 @@ public interface WxCpTpDepartmentService {
   /**
    * <pre>
    * 部门管理接口 - 获取部门列表.
-   * 详情请见: https://work.weixin.qq.com/api/doc#90000/90135/90208
+   * 详情请见: <a href="https://work.weixin.qq.com/api/doc#90000/90135/90208">...</a>
    * </pre>
    *
    * @param corpId the corp id
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpIdConvertService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpIdConvertService.java
index 78c52d5c36..10268bcb31 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpIdConvertService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpIdConvertService.java
@@ -6,8 +6,6 @@
 import me.chanjar.weixin.cp.bean.WxCpTpTagIdListConvertResult;
 import me.chanjar.weixin.cp.bean.WxCpTpUnionidToExternalUseridResult;
 
-import java.util.List;
-
 /**
  * <pre>
  *  企业微信三方应用ID转换接口
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpService.java
index 286f2e9673..5c433c0b49 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/WxCpTpService.java
@@ -371,7 +371,9 @@ public interface WxCpTpService {
 
   /**
    * <pre>
-   * 获取访问用户身份
+   * 获取登录/访问用户身份
+   * 1、<a href="https://developer.work.weixin.qq.com/document/path/91121">网页授权登录对应的文档</a>
+   * 2、<a href="https://developer.work.weixin.qq.com/document/path/98179">企业微信web登录对应的文档</a>
    * </pre>
    *
    * @param code the code
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImpl.java
index aa874f8549..9d620264c4 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/BaseWxCpTpServiceImpl.java
@@ -104,7 +104,7 @@ public boolean checkSignature(String msgSignature, String timestamp, String nonc
       return SHA1.gen(this.configStorage.getToken(), timestamp, nonce, data)
         .equals(msgSignature);
     } 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;
     }
   }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpIdConvertServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpIdConvertServiceImpl.java
index 7d0d80b452..6e14e6bbb9 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpIdConvertServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpIdConvertServiceImpl.java
@@ -14,8 +14,6 @@
 import me.chanjar.weixin.cp.tp.service.WxCpTpIdConvertService;
 import me.chanjar.weixin.cp.tp.service.WxCpTpService;
 
-import java.util.List;
-
 
 /**
  * @author cocoa
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImpl.java
index a128afd7e6..a5948a99c4 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceApacheHttpClientImpl.java
@@ -1,27 +1,25 @@
 package me.chanjar.weixin.cp.tp.service.impl;
 
-
 import com.google.gson.JsonObject;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.error.WxRuntimeException;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
+import me.chanjar.weixin.common.util.http.apache.ApacheBasicResponseHandler;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
 import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
 import me.chanjar.weixin.common.util.json.GsonParser;
 import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
 import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
-import org.apache.http.Consts;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.BasicResponseHandler;
 import org.apache.http.impl.client.CloseableHttpClient;
 
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 
 /**
  * The type Wx cp tp service apache http client.
@@ -43,8 +41,8 @@ public HttpHost getRequestHttpProxy() {
   }
 
   @Override
-  public HttpType getRequestType() {
-    return HttpType.APACHE_HTTP;
+  public HttpClientType getRequestType() {
+    return HttpClientType.APACHE_HTTP;
   }
 
   @Override
@@ -65,23 +63,17 @@ public String getSuiteAccessToken(boolean forceRefresh) throws WxErrorException
         jsonObject.addProperty("suite_id", this.configStorage.getSuiteId());
         jsonObject.addProperty("suite_secret", this.configStorage.getSuiteSecret());
         jsonObject.addProperty("suite_ticket", this.getSuiteTicket());
-        StringEntity entity = new StringEntity(jsonObject.toString(), Consts.UTF_8);
+        StringEntity entity = new StringEntity(jsonObject.toString(), StandardCharsets.UTF_8);
         httpPost.setEntity(entity);
 
-        String resultContent;
-        try (CloseableHttpClient httpclient = getRequestHttpClient();
-             CloseableHttpResponse response = httpclient.execute(httpPost)) {
-          resultContent = new BasicResponseHandler().handleResponse(response);
-        } finally {
-          httpPost.releaseConnection();
-        }
+        String resultContent = getRequestHttpClient().execute(httpPost, ApacheBasicResponseHandler.INSTANCE);
         WxError error = WxError.fromJson(resultContent, WxType.CP);
         if (error.getErrorCode() != 0) {
           throw new WxErrorException(error);
         }
         jsonObject = GsonParser.parse(resultContent);
         String suiteAccussToken = jsonObject.get("suite_access_token").getAsString();
-        Integer expiresIn = jsonObject.get("expires_in").getAsInt();
+        int expiresIn = jsonObject.get("expires_in").getAsInt();
         this.configStorage.updateSuiteAccessToken(suiteAccussToken, expiresIn);
       } catch (IOException e) {
         throw new WxRuntimeException(e);
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceHttpComponentsImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceHttpComponentsImpl.java
new file mode 100644
index 0000000000..419394a070
--- /dev/null
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/tp/service/impl/WxCpTpServiceHttpComponentsImpl.java
@@ -0,0 +1,106 @@
+package me.chanjar.weixin.cp.tp.service.impl;
+
+import com.google.gson.JsonObject;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
+import me.chanjar.weixin.common.util.http.HttpClientType;
+import me.chanjar.weixin.common.util.http.hc.BasicResponseHandler;
+import me.chanjar.weixin.common.util.http.hc.DefaultHttpComponentsClientBuilder;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsClientBuilder;
+import me.chanjar.weixin.common.util.json.GsonParser;
+import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
+import me.chanjar.weixin.cp.constant.WxCpApiPathConsts;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * The type Wx cp tp service apache http client.
+ *
+ * @author altusea
+ */
+public class WxCpTpServiceHttpComponentsImpl extends BaseWxCpTpServiceImpl<CloseableHttpClient, HttpHost> {
+  private CloseableHttpClient httpClient;
+  private HttpHost httpProxy;
+
+  @Override
+  public CloseableHttpClient getRequestHttpClient() {
+    return httpClient;
+  }
+
+  @Override
+  public HttpHost getRequestHttpProxy() {
+    return httpProxy;
+  }
+
+  @Override
+  public HttpClientType getRequestType() {
+    return HttpClientType.HTTP_COMPONENTS;
+  }
+
+  @Override
+  public String getSuiteAccessToken(boolean forceRefresh) throws WxErrorException {
+    if (!this.configStorage.isSuiteAccessTokenExpired() && !forceRefresh) {
+      return this.configStorage.getSuiteAccessToken();
+    }
+
+    synchronized (this.globalSuiteAccessTokenRefreshLock) {
+      try {
+        HttpPost httpPost = new HttpPost(configStorage.getApiUrl(WxCpApiPathConsts.Tp.GET_SUITE_TOKEN));
+        if (this.httpProxy != null) {
+          RequestConfig config = RequestConfig.custom()
+            .setProxy(this.httpProxy).build();
+          httpPost.setConfig(config);
+        }
+        JsonObject jsonObject = new JsonObject();
+        jsonObject.addProperty("suite_id", this.configStorage.getSuiteId());
+        jsonObject.addProperty("suite_secret", this.configStorage.getSuiteSecret());
+        jsonObject.addProperty("suite_ticket", this.getSuiteTicket());
+        StringEntity entity = new StringEntity(jsonObject.toString(), StandardCharsets.UTF_8);
+        httpPost.setEntity(entity);
+
+        String resultContent = getRequestHttpClient().execute(httpPost, BasicResponseHandler.INSTANCE);
+        WxError error = WxError.fromJson(resultContent, WxType.CP);
+        if (error.getErrorCode() != 0) {
+          throw new WxErrorException(error);
+        }
+        jsonObject = GsonParser.parse(resultContent);
+        String suiteAccussToken = jsonObject.get("suite_access_token").getAsString();
+        int expiresIn = jsonObject.get("expires_in").getAsInt();
+        this.configStorage.updateSuiteAccessToken(suiteAccussToken, expiresIn);
+      } catch (IOException e) {
+        throw new WxRuntimeException(e);
+      }
+    }
+    return this.configStorage.getSuiteAccessToken();
+  }
+
+  @Override
+  public void initHttp() {
+    HttpComponentsClientBuilder apacheHttpClientBuilder = DefaultHttpComponentsClientBuilder.get();
+
+    apacheHttpClientBuilder.httpProxyHost(this.configStorage.getHttpProxyHost())
+      .httpProxyPort(this.configStorage.getHttpProxyPort())
+      .httpProxyUsername(this.configStorage.getHttpProxyUsername())
+      .httpProxyPassword(this.configStorage.getHttpProxyPassword().toCharArray());
+
+    if (this.configStorage.getHttpProxyHost() != null && this.configStorage.getHttpProxyPort() > 0) {
+      this.httpProxy = new HttpHost(this.configStorage.getHttpProxyHost(), this.configStorage.getHttpProxyPort());
+    }
+
+    this.httpClient = apacheHttpClientBuilder.build();
+  }
+
+  @Override
+  public WxCpTpConfigStorage getWxCpTpConfigStorage() {
+    return this.configStorage;
+  }
+
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpChatGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpChatGsonAdapter.java
index e3a03ffab3..0e78465ead 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpChatGsonAdapter.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpChatGsonAdapter.java
@@ -1,11 +1,3 @@
-/*
- * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved.
- *
- * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended
- * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction
- * arose from modification of the original source, or other redistribution of this source
- * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD.
- */
 package me.chanjar.weixin.cp.util.json;
 
 import com.google.gson.*;
@@ -23,46 +15,44 @@
  */
 public class WxCpChatGsonAdapter implements JsonSerializer<WxCpChat>, JsonDeserializer<WxCpChat> {
 
+  public static final String FIELD_CHAT_ID = "chatid";
+  public static final String FIELD_NAME = "name";
+  public static final String FIELD_OWNER = "owner";
+  public static final String FIELD_USER_LIST = "userlist";
+
   @Override
   public JsonElement serialize(WxCpChat chat, Type typeOfSrc, JsonSerializationContext context) {
     JsonObject json = new JsonObject();
-    if (chat.getId() != null) {
-      json.addProperty("chatid", chat.getId());
-    }
-    if (chat.getName() != null) {
-      json.addProperty("name", chat.getName());
-    }
-    if (chat.getOwner() != null) {
-      json.addProperty("owner", chat.getOwner());
-    }
-    if (chat.getUsers() != null) {
+    addPropertyIfNotNull(json, FIELD_CHAT_ID, chat.getId());
+    addPropertyIfNotNull(json, FIELD_NAME, chat.getName());
+    addPropertyIfNotNull(json, FIELD_OWNER, chat.getOwner());
+    if (chat.getUsers() != null && !chat.getUsers().isEmpty()) {
       JsonArray users = new JsonArray();
-      for (String user : chat.getUsers()) {
-        users.add(user);
-      }
-      json.add("userlist", users);
+      chat.getUsers().forEach(users::add);
+      json.add(FIELD_USER_LIST, users);
     }
     return json;
   }
 
+  private void addPropertyIfNotNull(JsonObject json, String key, String value) {
+    if (value != null) {
+      json.addProperty(key, value);
+    }
+  }
+
   @Override
   public WxCpChat deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
     JsonObject chatJson = json.getAsJsonObject();
-
     WxCpChat chat = new WxCpChat();
     chat.setId(GsonHelper.getAsString(chatJson.get("chatid")));
     chat.setName(GsonHelper.getAsString(chatJson.get("name")));
     chat.setOwner(GsonHelper.getAsString(chatJson.get("owner")));
-
     JsonArray usersJson = chatJson.getAsJsonArray("userlist");
-    if (usersJson != null) {
+    if (usersJson != null && !usersJson.isEmpty()) {
       List<String> users = new ArrayList<>(usersJson.size());
+      usersJson.forEach(e -> users.add(e.getAsString()));
       chat.setUsers(users);
-      for (JsonElement userJson : usersJson) {
-        users.add(userJson.getAsString());
-      }
     }
-
     return chat;
   }
 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpDepartGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpDepartGsonAdapter.java
index af9344b701..72d367c431 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpDepartGsonAdapter.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpDepartGsonAdapter.java
@@ -1,11 +1,3 @@
-/*
- * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved.
- *
- * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended
- * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction
- * arose from modification of the original source, or other redistribution of this source
- * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD.
- */
 package me.chanjar.weixin.cp.util.json;
 
 import com.google.gson.*;
@@ -13,6 +5,8 @@
 import me.chanjar.weixin.cp.bean.WxCpDepart;
 
 import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * WxCpDepart的gson适配器.
@@ -30,60 +24,47 @@ public class WxCpDepartGsonAdapter implements JsonSerializer<WxCpDepart>, JsonDe
   @Override
   public JsonElement serialize(WxCpDepart group, Type typeOfSrc, JsonSerializationContext context) {
     JsonObject json = new JsonObject();
-    if (group.getId() != null) {
-      json.addProperty(ID, group.getId());
-    }
-    if (group.getName() != null) {
-      json.addProperty(NAME, group.getName());
-    }
-    if (group.getEnName() != null) {
-      json.addProperty(EN_NAME, group.getEnName());
-    }
-    if (group.getDepartmentLeader() != null) {
+    addPropertyIfNotNull(json, ID, group.getId());
+    addPropertyIfNotNull(json, NAME, group.getName());
+    addPropertyIfNotNull(json, EN_NAME, group.getEnName());
+    if (group.getDepartmentLeader() != null && group.getDepartmentLeader().length > 0) {
       JsonArray jsonArray = new JsonArray();
-      for (String department : group.getDepartmentLeader()) {
-        jsonArray.add(new JsonPrimitive(department));
-      }
+      Arrays.stream(group.getDepartmentLeader()).filter(Objects::nonNull).forEach(jsonArray::add);
       json.add(DEPARTMENT_LEADER, jsonArray);
     }
-    if (group.getParentId() != null) {
-      json.addProperty(PARENT_ID, group.getParentId());
-    }
-    if (group.getOrder() != null) {
-      json.addProperty(ORDER, String.valueOf(group.getOrder()));
-    }
+    addPropertyIfNotNull(json, PARENT_ID, group.getParentId());
+    addPropertyIfNotNull(json, ORDER, group.getOrder());
     return json;
   }
 
+  private void addPropertyIfNotNull(JsonObject json, String key, Object value) {
+    if (value != null) {
+      if (value instanceof Number) {
+        json.addProperty(key, (Number) value);
+      } else {
+        json.addProperty(key, value.toString());
+      }
+    }
+  }
+
   @Override
   public WxCpDepart deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
     throws JsonParseException {
     WxCpDepart depart = new WxCpDepart();
     JsonObject departJson = json.getAsJsonObject();
-    if (departJson.get(ID) != null && !departJson.get(ID).isJsonNull()) {
-      depart.setId(GsonHelper.getAsLong(departJson.get(ID)));
-    }
-    if (departJson.get(NAME) != null && !departJson.get(NAME).isJsonNull()) {
-      depart.setName(GsonHelper.getAsString(departJson.get(NAME)));
-    }
-    if (departJson.get(EN_NAME) != null && !departJson.get(EN_NAME).isJsonNull()) {
-      depart.setEnName(GsonHelper.getAsString(departJson.get(EN_NAME)));
-    }
-    if (departJson.getAsJsonArray(DEPARTMENT_LEADER) != null && !departJson.get(DEPARTMENT_LEADER).isJsonNull()) {
-      JsonArray jsonArray = departJson.getAsJsonArray(DEPARTMENT_LEADER);
+    depart.setId(GsonHelper.getAsLong(departJson.get(ID)));
+    depart.setName(GsonHelper.getAsString(departJson.get(NAME)));
+    depart.setEnName(GsonHelper.getAsString(departJson.get(EN_NAME)));
+    JsonArray jsonArray = departJson.getAsJsonArray(DEPARTMENT_LEADER);
+    if (jsonArray != null && !jsonArray.isJsonNull()) {
       String[] departments = new String[jsonArray.size()];
-      int i = 0;
-      for (JsonElement jsonElement : jsonArray) {
-        departments[i++] = jsonElement.getAsString();
+      for (int i = 0; i < jsonArray.size(); i++) {
+        departments[i] = jsonArray.get(i).getAsString();
       }
       depart.setDepartmentLeader(departments);
     }
-    if (departJson.get(ORDER) != null && !departJson.get(ORDER).isJsonNull()) {
-      depart.setOrder(GsonHelper.getAsLong(departJson.get(ORDER)));
-    }
-    if (departJson.get(PARENT_ID) != null && !departJson.get(PARENT_ID).isJsonNull()) {
-      depart.setParentId(GsonHelper.getAsLong(departJson.get(PARENT_ID)));
-    }
+    depart.setOrder(GsonHelper.getAsLong(departJson.get(ORDER)));
+    depart.setParentId(GsonHelper.getAsLong(departJson.get(PARENT_ID)));
     return depart;
   }
 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpTagGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpTagGsonAdapter.java
index 41a5b78400..2f830f7166 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpTagGsonAdapter.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpTagGsonAdapter.java
@@ -1,11 +1,3 @@
-/*
- * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved.
- *
- * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended
- * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction
- * arose from modification of the original source, or other redistribution of this source
- * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD.
- */
 package me.chanjar.weixin.cp.util.json;
 
 import com.google.gson.*;
@@ -21,19 +13,28 @@
  */
 public class WxCpTagGsonAdapter implements JsonSerializer<WxCpTag>, JsonDeserializer<WxCpTag> {
 
+  private static final String TAG_ID = "tagid";
+  private static final String TAG_NAME = "tagname";
+
   @Override
   public JsonElement serialize(WxCpTag tag, Type typeOfSrc, JsonSerializationContext context) {
     JsonObject o = new JsonObject();
-    o.addProperty("tagid", tag.getId());
-    o.addProperty("tagname", tag.getName());
+    addPropertyIfNotNull(o, TAG_ID, tag.getId());
+    addPropertyIfNotNull(o, TAG_NAME, tag.getName());
     return o;
   }
 
+  private void addPropertyIfNotNull(JsonObject obj, String key, String value) {
+    if (value != null) {
+      obj.addProperty(key, value);
+    }
+  }
+
   @Override
   public WxCpTag deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
     throws JsonParseException {
     JsonObject jsonObject = json.getAsJsonObject();
-    return new WxCpTag(GsonHelper.getString(jsonObject, "tagid"), GsonHelper.getString(jsonObject, "tagname"));
+    return new WxCpTag(GsonHelper.getString(jsonObject, TAG_ID), GsonHelper.getString(jsonObject, TAG_NAME));
   }
 
 }
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java
index 0c32ba0060..0da35ff7fb 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/json/WxCpUserGsonAdapter.java
@@ -1,12 +1,3 @@
-/*
- * KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved.
- *
- * This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended
- * only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction
- * arose from modification of the original source, or other redistribution of this source
- * is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD.
- */
-
 package me.chanjar.weixin.cp.util.json;
 
 import com.google.gson.*;
@@ -15,6 +6,8 @@
 import me.chanjar.weixin.cp.bean.WxCpUser;
 
 import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.stream.IntStream;
 
 import static me.chanjar.weixin.cp.bean.WxCpUser.*;
 
@@ -31,66 +24,78 @@ public class WxCpUserGsonAdapter implements JsonDeserializer<WxCpUser>, JsonSeri
   private static final String DEPARTMENT = "department";
   private static final String EXTERNAL_CORP_NAME = "external_corp_name";
   private static final String WECHAT_CHANNELS = "wechat_channels";
+  private static final String ORDER = "order";
+  private static final String POSITIONS = "positions";
+  private static final String USER_ID = "userid";
+  private static final String NEW_USER_ID = "new_userid";
+  private static final String NAME = "name";
+  private static final String POSITION = "position";
+  private static final String MOBILE = "mobile";
+  private static final String GENDER = "gender";
+  private static final String EMAIL = "email";
+  private static final String BIZ_MAIL = "biz_mail";
+  private static final String AVATAR = "avatar";
+  private static final String THUMB_AVATAR = "thumb_avatar";
+  private static final String ADDRESS = "address";
+  private static final String AVATAR_MEDIAID = "avatar_mediaid";
+  private static final String STATUS = "status";
+  private static final String ENABLE = "enable";
+  private static final String ALIAS = "alias";
+  private static final String IS_LEADER = "isleader";
+  private static final String IS_LEADER_IN_DEPT = "is_leader_in_dept";
+  private static final String HIDE_MOBILE = "hide_mobile";
+  private static final String ENGLISH_NAME = "english_name";
+  private static final String TELEPHONE = "telephone";
+  private static final String QR_CODE = "qr_code";
+  private static final String TO_INVITE = "to_invite";
+  private static final String OPEN_USER_ID = "open_userid";
+  private static final String MAIN_DEPARTMENT = "main_department";
+  private static final String DIRECT_LEADER = "direct_leader";
+  private static final String TYPE = "type";
+  private static final String VALUE = "value";
+  private static final String TEXT = "text";
+  private static final String WEB = "web";
+  private static final String MINIPROGRAM = "miniprogram";
+  private static final String URL = "url";
+  private static final String TITLE = "title";
+  private static final String APPID = "appid";
+  private static final String PAGE_PATH = "pagepath";
+  private static final String ATTRS = "attrs";
+  private static final String NICKNAME = "nickname";
 
   @Override
   public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
     JsonObject o = json.getAsJsonObject();
     WxCpUser user = new WxCpUser();
 
-    if (o.get(DEPARTMENT) != null) {
-      JsonArray departJsonArray = o.get(DEPARTMENT).getAsJsonArray();
-      Long[] departIds = new Long[departJsonArray.size()];
-      int i = 0;
-      for (JsonElement jsonElement : departJsonArray) {
-        departIds[i++] = jsonElement.getAsLong();
-      }
-      user.setDepartIds(departIds);
-    }
-
-    if (o.get("order") != null) {
-      JsonArray departJsonArray = o.get("order").getAsJsonArray();
-      Integer[] orders = new Integer[departJsonArray.size()];
-      int i = 0;
-      for (JsonElement jsonElement : departJsonArray) {
-        orders[i++] = jsonElement.getAsInt();
-      }
-      user.setOrders(orders);
-    }
-
-    if (o.get("positions") != null) {
-      JsonArray positionJsonArray = o.get("positions").getAsJsonArray();
-      String[] positions = new String[positionJsonArray.size()];
-      int i = 0;
-      for (JsonElement jsonElement : positionJsonArray) {
-        positions[i++] = jsonElement.getAsString();
-      }
-      user.setPositions(positions);
-    }
-
-    user.setUserId(GsonHelper.getString(o, "userid"));
-    user.setName(GsonHelper.getString(o, "name"));
-    user.setPosition(GsonHelper.getString(o, "position"));
-    user.setMobile(GsonHelper.getString(o, "mobile"));
-    user.setGender(Gender.fromCode(GsonHelper.getString(o, "gender")));
-    user.setEmail(GsonHelper.getString(o, "email"));
-    user.setBizMail(GsonHelper.getString(o, "biz_mail"));
-    user.setAvatar(GsonHelper.getString(o, "avatar"));
-    user.setThumbAvatar(GsonHelper.getString(o, "thumb_avatar"));
-    user.setAddress(GsonHelper.getString(o, "address"));
-    user.setAvatarMediaId(GsonHelper.getString(o, "avatar_mediaid"));
-    user.setStatus(GsonHelper.getInteger(o, "status"));
-    user.setEnable(GsonHelper.getInteger(o, "enable"));
-    user.setAlias(GsonHelper.getString(o, "alias"));
-    user.setIsLeader(GsonHelper.getInteger(o, "isleader"));
-    user.setIsLeaderInDept(GsonHelper.getIntArray(o, "is_leader_in_dept"));
-    user.setHideMobile(GsonHelper.getInteger(o, "hide_mobile"));
-    user.setEnglishName(GsonHelper.getString(o, "english_name"));
-    user.setTelephone(GsonHelper.getString(o, "telephone"));
-    user.setQrCode(GsonHelper.getString(o, "qr_code"));
-    user.setToInvite(GsonHelper.getBoolean(o, "to_invite"));
-    user.setOpenUserId(GsonHelper.getString(o, "open_userid"));
-    user.setMainDepartment(GsonHelper.getString(o, "main_department"));
-    user.setDirectLeader(GsonHelper.getStringArray(o, "direct_leader"));
+    user.setDepartIds(parseJsonArrayToLongArray(o, DEPARTMENT));
+    user.setOrders(parseJsonArrayToIntegerArray(o, ORDER));
+    user.setPositions(parseJsonArrayToStringArray(o, POSITIONS));
+
+    user.setUserId(GsonHelper.getString(o, USER_ID));
+    user.setName(GsonHelper.getString(o, NAME));
+    user.setPosition(GsonHelper.getString(o, POSITION));
+    user.setMobile(GsonHelper.getString(o, MOBILE));
+    user.setGender(Gender.fromCode(GsonHelper.getString(o, GENDER)));
+    user.setEmail(GsonHelper.getString(o, EMAIL));
+    user.setBizMail(GsonHelper.getString(o, BIZ_MAIL));
+    user.setAvatar(GsonHelper.getString(o, AVATAR));
+    user.setThumbAvatar(GsonHelper.getString(o, THUMB_AVATAR));
+    user.setAddress(GsonHelper.getString(o, ADDRESS));
+    user.setAvatarMediaId(GsonHelper.getString(o, AVATAR_MEDIAID));
+    user.setStatus(GsonHelper.getInteger(o, STATUS));
+    user.setEnable(GsonHelper.getInteger(o, ENABLE));
+    user.setAlias(GsonHelper.getString(o, ALIAS));
+    user.setIsLeader(GsonHelper.getInteger(o, IS_LEADER));
+    user.setIsLeaderInDept(GsonHelper.getIntArray(o, IS_LEADER_IN_DEPT));
+    user.setHideMobile(GsonHelper.getInteger(o, HIDE_MOBILE));
+    user.setEnglishName(GsonHelper.getString(o, ENGLISH_NAME));
+    user.setTelephone(GsonHelper.getString(o, TELEPHONE));
+    user.setQrCode(GsonHelper.getString(o, QR_CODE));
+    user.setToInvite(GsonHelper.getBoolean(o, TO_INVITE));
+    user.setOpenUserId(GsonHelper.getString(o, OPEN_USER_ID));
+    user.setMainDepartment(GsonHelper.getString(o, MAIN_DEPARTMENT));
+    user.setDirectLeader(GsonHelper.getStringArray(o, DIRECT_LEADER));
 
     if (GsonHelper.isNotNull(o.get(EXTRA_ATTR))) {
       this.buildExtraAttrs(o, user);
@@ -102,8 +107,9 @@ public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationC
       JsonElement jsonElement = o.get(EXTERNAL_PROFILE).getAsJsonObject().get(WECHAT_CHANNELS);
       if (jsonElement != null) {
         JsonObject asJsonObject = jsonElement.getAsJsonObject();
-        user.setWechatChannels(WechatChannels.builder().nickname(GsonHelper.getString(asJsonObject, "nickname")).status(GsonHelper.getInteger(asJsonObject, "status")).build());
+        user.setWechatChannels(WechatChannels.builder().nickname(GsonHelper.getString(asJsonObject, NICKNAME)).status(GsonHelper.getInteger(asJsonObject, STATUS)).build());
       }
+
       this.buildExternalAttrs(o, user);
     }
 
@@ -112,29 +118,66 @@ public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationC
     return user;
   }
 
+  private Long[] parseJsonArrayToLongArray(JsonObject o, String key) {
+    JsonElement element = o.get(key);
+    if (element == null || !element.isJsonArray()) {
+      return null;
+    }
+    JsonArray jsonArray = element.getAsJsonArray();
+    return IntStream.range(0, jsonArray.size())
+        .mapToObj(i -> jsonArray.get(i).getAsLong())
+        .toArray(Long[]::new);
+  }
+
+  private Integer[] parseJsonArrayToIntegerArray(JsonObject o, String key) {
+    JsonElement element = o.get(key);
+    if (element == null || !element.isJsonArray()) {
+      return null;
+    }
+    JsonArray jsonArray = element.getAsJsonArray();
+    return IntStream.range(0, jsonArray.size())
+        .mapToObj(i -> jsonArray.get(i).getAsInt())
+        .toArray(Integer[]::new);
+  }
+
+  private String[] parseJsonArrayToStringArray(JsonObject o, String key) {
+    JsonElement element = o.get(key);
+    if (element == null || !element.isJsonArray()) {
+      return null;
+    }
+    JsonArray jsonArray = element.getAsJsonArray();
+    return IntStream.range(0, jsonArray.size())
+        .mapToObj(i -> jsonArray.get(i).getAsString())
+        .toArray(String[]::new);
+  }
+
   private void buildExtraAttrs(JsonObject o, WxCpUser user) {
-    JsonArray attrJsonElements = o.get(EXTRA_ATTR).getAsJsonObject().get("attrs").getAsJsonArray();
+    JsonArray attrJsonElements = o.get(EXTRA_ATTR).getAsJsonObject().get(ATTRS).getAsJsonArray();
     for (JsonElement attrJsonElement : attrJsonElements) {
-      final Integer type = GsonHelper.getInteger(attrJsonElement.getAsJsonObject(), "type");
+      final Integer type = GsonHelper.getInteger(attrJsonElement.getAsJsonObject(), TYPE);
       final Attr attr = new Attr().setType(type)
-        .setName(GsonHelper.getString(attrJsonElement.getAsJsonObject(), "name"));
+        .setName(GsonHelper.getString(attrJsonElement.getAsJsonObject(), NAME));
       user.getExtAttrs().add(attr);
 
       if (type == null) {
-        attr.setTextValue(GsonHelper.getString(attrJsonElement.getAsJsonObject(), "value"));
+        attr.setTextValue(GsonHelper.getString(attrJsonElement.getAsJsonObject(), VALUE));
         continue;
       }
 
       switch (type) {
         case 0: {
-          attr.setTextValue(GsonHelper.getString(attrJsonElement.getAsJsonObject().get("text").getAsJsonObject(),
-            "value"));
+          JsonElement textJsonElement = attrJsonElement.getAsJsonObject().get(TEXT);
+          if (textJsonElement != null && !textJsonElement.isJsonNull() && textJsonElement.isJsonObject()) {
+            attr.setTextValue(GsonHelper.getString(textJsonElement.getAsJsonObject(), VALUE));
+          } else {
+            attr.setTextValue(null); // Clear or set a default value to avoid stale data
+          }
           break;
         }
         case 1: {
-          final JsonObject web = attrJsonElement.getAsJsonObject().get("web").getAsJsonObject();
-          attr.setWebTitle(GsonHelper.getString(web, "title"))
-            .setWebUrl(GsonHelper.getString(web, "url"));
+          final JsonObject web = attrJsonElement.getAsJsonObject().get(WEB).getAsJsonObject();
+          attr.setWebTitle(GsonHelper.getString(web, TITLE))
+            .setWebUrl(GsonHelper.getString(web, URL));
           break;
         }
         default://ignored
@@ -150,8 +193,8 @@ private void buildExternalAttrs(JsonObject o, WxCpUser user) {
 
     JsonArray attrJsonElements = jsonElement.getAsJsonArray();
     for (JsonElement element : attrJsonElements) {
-      final Integer type = GsonHelper.getInteger(element.getAsJsonObject(), "type");
-      final String name = GsonHelper.getString(element.getAsJsonObject(), "name");
+      final Integer type = GsonHelper.getInteger(element.getAsJsonObject(), TYPE);
+      final String name = GsonHelper.getString(element.getAsJsonObject(), NAME);
 
       if (type == null) {
         continue;
@@ -163,32 +206,32 @@ private void buildExternalAttrs(JsonObject o, WxCpUser user) {
             .add(ExternalAttribute.builder()
               .type(type)
               .name(name)
-              .value(GsonHelper.getString(element.getAsJsonObject().get("text").getAsJsonObject(), "value"))
+              .value(GsonHelper.getString(element.getAsJsonObject().get(TEXT).getAsJsonObject(), VALUE))
               .build()
             );
           break;
         }
         case 1: {
-          final JsonObject web = element.getAsJsonObject().get("web").getAsJsonObject();
+          final JsonObject web = element.getAsJsonObject().get(WEB).getAsJsonObject();
           user.getExternalAttrs()
             .add(ExternalAttribute.builder()
               .type(type)
               .name(name)
-              .url(GsonHelper.getString(web, "url"))
-              .title(GsonHelper.getString(web, "title"))
+              .url(GsonHelper.getString(web, URL))
+              .title(GsonHelper.getString(web, TITLE))
               .build()
             );
           break;
         }
         case 2: {
-          final JsonObject miniprogram = element.getAsJsonObject().get("miniprogram").getAsJsonObject();
+          final JsonObject miniprogram = element.getAsJsonObject().get(MINIPROGRAM).getAsJsonObject();
           user.getExternalAttrs()
             .add(ExternalAttribute.builder()
               .type(type)
               .name(name)
-              .appid(GsonHelper.getString(miniprogram, "appid"))
-              .pagePath(GsonHelper.getString(miniprogram, "pagepath"))
-              .title(GsonHelper.getString(miniprogram, "title"))
+              .appid(GsonHelper.getString(miniprogram, APPID))
+              .pagePath(GsonHelper.getString(miniprogram, PAGE_PATH))
+              .title(GsonHelper.getString(miniprogram, TITLE))
               .build()
             );
           break;
@@ -201,97 +244,70 @@ private void buildExternalAttrs(JsonObject o, WxCpUser user) {
   @Override
   public JsonElement serialize(WxCpUser user, Type typeOfSrc, JsonSerializationContext context) {
     JsonObject o = new JsonObject();
-    this.addProperty(o, "userid", user.getUserId());
-    this.addProperty(o, "new_userid", user.getNewUserId());
-    this.addProperty(o, "name", user.getName());
-    if (user.getDepartIds() != null) {
-      JsonArray jsonArray = new JsonArray();
-      for (Long departId : user.getDepartIds()) {
-        jsonArray.add(new JsonPrimitive(departId));
-      }
-      o.add("department", jsonArray);
-    }
+    addProperty(o, USER_ID, user.getUserId());
+    addProperty(o, NEW_USER_ID, user.getNewUserId());
+    addProperty(o, NAME, user.getName());
 
-    if (user.getOrders() != null) {
-      JsonArray jsonArray = new JsonArray();
-      for (Integer order : user.getOrders()) {
-        jsonArray.add(new JsonPrimitive(order));
-      }
-      o.add("order", jsonArray);
-    }
-
-    this.addProperty(o, "position", user.getPosition());
+    addArrayProperty(o, DEPARTMENT, user.getDepartIds());
+    addArrayProperty(o, ORDER, user.getOrders());
+    addProperty(o, POSITION, user.getPosition());
+    addArrayProperty(o, POSITIONS, user.getPositions());
 
-    if (user.getPositions() != null) {
-      JsonArray jsonArray = new JsonArray();
-      for (String position : user.getPositions()) {
-        jsonArray.add(new JsonPrimitive(position));
-      }
-      o.add("positions", jsonArray);
-    }
-
-    this.addProperty(o, "mobile", user.getMobile());
+    addProperty(o, MOBILE, user.getMobile());
     if (user.getGender() != null) {
-      o.addProperty("gender", user.getGender().getCode());
+      o.addProperty(GENDER, user.getGender().getCode());
     }
-    this.addProperty(o, "email", user.getEmail());
-    this.addProperty(o, "biz_mail", user.getBizMail());
-    this.addProperty(o, "avatar", user.getAvatar());
-    this.addProperty(o, "thumb_avatar", user.getThumbAvatar());
-    this.addProperty(o, "address", user.getAddress());
-    this.addProperty(o, "avatar_mediaid", user.getAvatarMediaId());
-    this.addProperty(o, "status", user.getStatus());
-    this.addProperty(o, "enable", user.getEnable());
-    this.addProperty(o, "alias", user.getAlias());
-    this.addProperty(o, "isleader", user.getIsLeader());
+    addProperty(o, EMAIL, user.getEmail());
+    addProperty(o, BIZ_MAIL, user.getBizMail());
+    addProperty(o, AVATAR, user.getAvatar());
+    addProperty(o, THUMB_AVATAR, user.getThumbAvatar());
+    addProperty(o, ADDRESS, user.getAddress());
+    addProperty(o, AVATAR_MEDIAID, user.getAvatarMediaId());
+    addProperty(o, STATUS, user.getStatus());
+    addProperty(o, ENABLE, user.getEnable());
+    addProperty(o, ALIAS, user.getAlias());
+    addProperty(o, IS_LEADER, user.getIsLeader());
     if (user.getIsLeaderInDept() != null && user.getIsLeaderInDept().length > 0) {
       JsonArray ary = new JsonArray();
-      for (int item : user.getIsLeaderInDept()) {
-        ary.add(item);
-      }
-      o.add("is_leader_in_dept", ary);
+      Arrays.stream(user.getIsLeaderInDept()).forEach(ary::add);
+      o.add(IS_LEADER_IN_DEPT, ary);
     }
-    this.addProperty(o, "hide_mobile", user.getHideMobile());
-    this.addProperty(o, "english_name", user.getEnglishName());
-    this.addProperty(o, "telephone", user.getTelephone());
-    this.addProperty(o, "qr_code", user.getQrCode());
+    addProperty(o, HIDE_MOBILE, user.getHideMobile());
+    addProperty(o, ENGLISH_NAME, user.getEnglishName());
+    addProperty(o, TELEPHONE, user.getTelephone());
+    addProperty(o, QR_CODE, user.getQrCode());
     if (user.getToInvite() != null) {
-      o.addProperty("to_invite", user.getToInvite());
+      o.addProperty(TO_INVITE, user.getToInvite());
     }
-    this.addProperty(o, "main_department", user.getMainDepartment());
+    addProperty(o, MAIN_DEPARTMENT, user.getMainDepartment());
+
+    addArrayProperty(o, DIRECT_LEADER, user.getDirectLeader());
 
-    if (user.getDirectLeader() != null && user.getDirectLeader().length > 0) {
-      JsonArray ary = new JsonArray();
-      for (String item : user.getDirectLeader()) {
-        ary.add(item);
-      }
-      o.add("direct_leader", ary);
-    }
     if (!user.getExtAttrs().isEmpty()) {
       JsonArray attrsJsonArray = new JsonArray();
       for (Attr attr : user.getExtAttrs()) {
-        JsonObject attrJson = GsonHelper.buildJsonObject("type", attr.getType(),
-          "name", attr.getName());
+        JsonObject attrJson = GsonHelper.buildJsonObject(TYPE, attr.getType(),
+          NAME, attr.getName());
         attrsJsonArray.add(attrJson);
 
         if (attr.getType() == null) {
-          attrJson.addProperty("name", attr.getName());
-          attrJson.addProperty("value", attr.getTextValue());
+          attrJson.addProperty(NAME, attr.getName());
+          attrJson.addProperty(VALUE, attr.getTextValue());
           continue;
         }
 
         switch (attr.getType()) {
           case 0:
-            attrJson.add("text", GsonHelper.buildJsonObject("value", attr.getTextValue()));
+            attrJson.add(TEXT, GsonHelper.buildJsonObject(VALUE, attr.getTextValue()));
             break;
           case 1:
-            attrJson.add("web", GsonHelper.buildJsonObject("url", attr.getWebUrl(), "title", attr.getWebTitle()));
+            attrJson.add(WEB, GsonHelper.buildJsonObject(URL, attr.getWebUrl(), TITLE, attr.getWebTitle()));
             break;
           default: //ignored
         }
       }
       JsonObject attrsJson = new JsonObject();
-      attrsJson.add("attrs", attrsJsonArray);
+      attrsJson.add(ATTRS, attrsJsonArray);
       o.add(EXTRA_ATTR, attrsJson);
     }
 
@@ -303,15 +319,15 @@ public JsonElement serialize(WxCpUser user, Type typeOfSrc, JsonSerializationCon
     this.addProperty(attrsJson, EXTERNAL_CORP_NAME, user.getExternalCorpName());
 
     if (user.getWechatChannels() != null) {
-      attrsJson.add(WECHAT_CHANNELS, GsonHelper.buildJsonObject("nickname", user.getWechatChannels().getNickname(),
-        "status", user.getWechatChannels().getStatus()));
+      attrsJson.add(WECHAT_CHANNELS, GsonHelper.buildJsonObject(NICKNAME, user.getWechatChannels().getNickname(),
+        STATUS, user.getWechatChannels().getStatus()));
     }
 
     if (!user.getExternalAttrs().isEmpty()) {
       JsonArray attrsJsonArray = new JsonArray();
       for (ExternalAttribute attr : user.getExternalAttrs()) {
-        JsonObject attrJson = GsonHelper.buildJsonObject("type", attr.getType(),
-          "name", attr.getName());
+        JsonObject attrJson = GsonHelper.buildJsonObject(TYPE, attr.getType(),
+          NAME, attr.getName());
 
         attrsJsonArray.add(attrJson);
 
@@ -321,14 +337,14 @@ public JsonElement serialize(WxCpUser user, Type typeOfSrc, JsonSerializationCon
 
         switch (attr.getType()) {
           case 0:
-            attrJson.add("text", GsonHelper.buildJsonObject("value", attr.getValue()));
+            attrJson.add(TEXT, GsonHelper.buildJsonObject(VALUE, attr.getValue()));
             break;
           case 1:
-            attrJson.add("web", GsonHelper.buildJsonObject("url", attr.getUrl(), "title", attr.getTitle()));
+            attrJson.add(WEB, GsonHelper.buildJsonObject(URL, attr.getUrl(), TITLE, attr.getTitle()));
             break;
           case 2:
-            attrJson.add("miniprogram", GsonHelper.buildJsonObject("appid", attr.getAppid(),
-              "pagepath", attr.getPagePath(), "title", attr.getTitle()));
+            attrJson.add(MINIPROGRAM, GsonHelper.buildJsonObject(APPID, attr.getAppid(),
+              PAGE_PATH, attr.getPagePath(), TITLE, attr.getTitle()));
             break;
           default://忽略
         }
@@ -340,15 +356,29 @@ public JsonElement serialize(WxCpUser user, Type typeOfSrc, JsonSerializationCon
     return o;
   }
 
-  private void addProperty(JsonObject object, String property, Integer value) {
-    if (value != null) {
-      object.addProperty(property, value);
+  private void addArrayProperty(JsonObject o, String key, Object[] array) {
+    if (array != null && array.length > 0) {
+      JsonArray jsonArray = new JsonArray();
+      Arrays.stream(array).forEach(item -> {
+        if (item instanceof Number) {
+          jsonArray.add((Number) item);
+        } else {
+          jsonArray.add(item.toString());
+        }
+      });
+      o.add(key, jsonArray);
     }
   }
 
-  private void addProperty(JsonObject object, String property, String value) {
+  private void addProperty(JsonObject object, String property, Object value) {
     if (value != null) {
-      object.addProperty(property, value);
+      if (value instanceof Number) {
+        object.addProperty(property, (Number) value);
+      } else if (value instanceof Boolean) {
+        object.addProperty(property, (Boolean) value);
+      } else {
+        object.addProperty(property, value.toString());
+      }
     }
   }
 
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java
index c4753befd2..098a781c64 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/util/xml/XStreamTransformer.java
@@ -17,7 +17,7 @@ public class XStreamTransformer {
   /**
    * The constant CLASS_2_XSTREAM_INSTANCE.
    */
-  protected static final Map<Class, XStream> CLASS_2_XSTREAM_INSTANCE = configXStreamInstance();
+  protected static final Map<Class<?>, XStream> CLASS_2_XSTREAM_INSTANCE = configXStreamInstance();
 
   /**
    * xml -> pojo
@@ -53,7 +53,7 @@ public static <T> T fromXml(Class<T> clazz, InputStream is) {
    * @param clz     类型
    * @param xStream xml解析器
    */
-  public static void register(Class clz, XStream xStream) {
+  public static void register(Class<?> clz, XStream xStream) {
     CLASS_2_XSTREAM_INSTANCE.put(clz, xStream);
   }
 
@@ -69,8 +69,8 @@ public static <T> String toXml(Class<T> clazz, T object) {
     return CLASS_2_XSTREAM_INSTANCE.get(clazz).toXML(object);
   }
 
-  private static Map<Class, XStream> configXStreamInstance() {
-    Map<Class, XStream> map = new HashMap<>();
+  private static Map<Class<?>, XStream> configXStreamInstance() {
+    Map<Class<?>, XStream> map = new HashMap<>();
     map.put(WxCpXmlMessage.class, configWxCpXmlMessage());
     map.put(WxCpXmlOutNewsMessage.class, configWxCpXmlOutNewsMessage());
     map.put(WxCpXmlOutTextMessage.class, configWxCpXmlOutTextMessage());
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpOaWeDriveServiceTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpOaWeDriveServiceTest.java
index dc1c458734..1364ab5a13 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpOaWeDriveServiceTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpOaWeDriveServiceTest.java
@@ -56,19 +56,19 @@ public void test() throws Exception {
     String fileId2 = "s.ww45d3e188865aca30.652091685u4h_f.652696024TU4P";
 
 
-    /**
+    /*
      * 获取分享链接
      */
-    WxCpFileShare fileShare = cpService.getOaWeDriveService().fileShare(uId, fileId2);
+    WxCpFileShare fileShare = cpService.getOaWeDriveService().fileShare(fileId2);
     log.info("获取分享链接返回结果为：{}", fileShare.toJson());
 
-    /**
+    /*
      * 分享设置
      */
-    WxCpBaseResp fileSetting = cpService.getOaWeDriveService().fileSetting(uId, fileId2, 2, 1);
+    WxCpBaseResp fileSetting = cpService.getOaWeDriveService().fileSetting(fileId2, 2, 1);
     log.info("分享设置返回结果为：{}", fileSetting.toJson());
 
-    /**
+    /*
      * 删除指定人
      */
     WxCpFileAclDelRequest aclDelRequest = new WxCpFileAclDelRequest();
@@ -87,7 +87,7 @@ public void test() throws Exception {
     WxCpBaseResp aclDel = cpService.getOaWeDriveService().fileAclDel(aclDelRequest);
     log.info("删除指定人返回结果为：{}", aclDel.toJson());
 
-    /**
+    /*
      * 新增指定人
      */
     WxCpFileAclAddRequest fileAclAdd = new WxCpFileAclAddRequest();
@@ -105,25 +105,24 @@ public void test() throws Exception {
     WxCpBaseResp result = cpService.getOaWeDriveService().fileAclAdd(fileAclAdd);
     log.info("返回结果为：{}", result.toJson());
 
-    /**
+    /*
      * 删除文件
      */
     ArrayList<String> fileIds = Lists.newArrayList();
     fileIds.add(fileId);
-    WxCpBaseResp fileDelete = cpService.getOaWeDriveService().fileDelete(uId, fileIds);
+    WxCpBaseResp fileDelete = cpService.getOaWeDriveService().fileDelete(fileIds);
     log.info("删除文件数据为：{}", fileDelete.toJson());
 
-    /**
-     * 文件信息
+    /*
+      文件信息
      */
-    WxCpFileInfo fileInfo = cpService.getOaWeDriveService().fileInfo(uId, fileId);
+    WxCpFileInfo fileInfo = cpService.getOaWeDriveService().fileInfo(fileId);
     log.info("fileInfo数据为：{}", fileInfo.toJson());
 
-    /**
-     * 移动文件
+    /*
+      移动文件
      */
     WxCpFileMoveRequest fileMoveRequest = new WxCpFileMoveRequest();
-    fileMoveRequest.setUserId(uId);
     fileMoveRequest.setFatherId(spId);
     fileMoveRequest.setReplace(true);
     fileMoveRequest.setFileId(new String[]{fileId});
@@ -131,23 +130,22 @@ public void test() throws Exception {
     WxCpFileMove fileMove = cpService.getOaWeDriveService().fileMove(fileMoveRequest);
     log.info("fileMove数据为：{}", fileMove.toJson());
 
-    /**
-     * 新建文件/微文档
+    /*
+      新建文件/微文档
      */
-    WxCpFileCreate fileCreate = cpService.getOaWeDriveService().fileCreate(uId, spId, spId, 3, "新建微文档1");
+    WxCpFileCreate fileCreate = cpService.getOaWeDriveService().fileCreate(spId, spId, 3, "新建微文档1");
     log.info("新建文件/微文档：{}", fileCreate.toJson());
 
-    /**
-     * 下载文件
+    /*
+      下载文件
      */
     WxCpFileDownload fileDownload = cpService.getOaWeDriveService().fileDownload(uId, fileId);
     log.info("下载文件为：{}", fileDownload.toJson());
 
-    /**
-     * 上传文件
+    /*
+      上传文件
      */
     WxCpFileUploadRequest fileUploadRequest = new WxCpFileUploadRequest();
-    fileUploadRequest.setUserId(uId);
     fileUploadRequest.setSpaceId(spId);
     fileUploadRequest.setFatherId(spId);
     fileUploadRequest.setFileName("第一个文件");
@@ -165,17 +163,16 @@ public void test() throws Exception {
     WxCpFileUpload fileUpload = cpService.getOaWeDriveService().fileUpload(fileUploadRequest);
     log.info("上传文件为：{}", fileUpload.toJson());
 
-    /**
-     * 重命名文件
+    /*
+      重命名文件
      */
-    WxCpFileRename fileRename = cpService.getOaWeDriveService().fileRename(uId, fileUpload.getFileId(), "新的名字呢");
+    WxCpFileRename fileRename = cpService.getOaWeDriveService().fileRename(fileUpload.getFileId(), "新的名字呢");
     log.info("重命名文件：{}", fileRename.toJson());
 
-    /**
-     * 获取文件列表
+    /*
+      获取文件列表
      */
     WxCpFileListRequest fileListRequest = new WxCpFileListRequest();
-    fileListRequest.setUserId(uId);
     fileListRequest.setSpaceId(spId);
     fileListRequest.setFatherId(spId);
     fileListRequest.setSortType(1);
@@ -185,7 +182,7 @@ public void test() throws Exception {
     WxCpFileList fileList = cpService.getOaWeDriveService().fileList(fileListRequest);
     log.info("获取文件列表为：{}", fileList.toJson());
 
-    /**
+    /*
      * 权限管理
      */
     WxCpSpaceSettingRequest spaceSettingRequest = new WxCpSpaceSettingRequest();
@@ -200,19 +197,19 @@ public void test() throws Exception {
     WxCpBaseResp spaceSetting = cpService.getOaWeDriveService().spaceSetting(spaceSettingRequest);
     log.info("权限管理信息为：{}", spaceSetting.toJson());
 
-    /**
+    /*
      * 获取邀请链接
      */
-    WxCpSpaceShare spaceShare = cpService.getOaWeDriveService().spaceShare(uId, spId);
+    WxCpSpaceShare spaceShare = cpService.getOaWeDriveService().spaceShare(spId);
     log.info("获取邀请链接信息为：{}", spaceShare.toJson());
 
-    /**
+    /*
      * 获取空间信息
      */
-    WxCpSpaceInfo data = cpService.getOaWeDriveService().spaceInfo(uId, spId);
+    WxCpSpaceInfo data = cpService.getOaWeDriveService().spaceInfo(spId);
     log.info("获取空间信息为：{}", data.toJson());
 
-    /**
+    /*
      * 移除成员/部门
      */
     WxCpSpaceAclDelRequest spaceAclDelRequest = new WxCpSpaceAclDelRequest();
@@ -231,7 +228,7 @@ public void test() throws Exception {
     WxCpBaseResp spaceAclDel = cpService.getOaWeDriveService().spaceAclDel(spaceAclDelRequest);
     log.info("移除成员/部门，返回数据为：{}", spaceAclDel.toJson());
 
-    /**
+    /*
      * 添加成员/部门
      * https://developer.work.weixin.qq.com/document/path/93656
      */
@@ -252,13 +249,13 @@ public void test() throws Exception {
     WxCpBaseResp wxCpBaseResp = cpService.getOaWeDriveService().spaceAclAdd(spaceAclAddRequest);
     log.info("添加成员/部门，返回数据为：{}", wxCpBaseResp.toJson());
 
-    /**
+    /*
      * 获取空间信息
      */
-    WxCpSpaceInfo spaceInfo = cpService.getOaWeDriveService().spaceInfo("WangKai", "s.ww45d3e188865aca30.652091685u4h");
+    WxCpSpaceInfo spaceInfo = cpService.getOaWeDriveService().spaceInfo("s.ww45d3e188865aca30.652091685u4h");
     log.info("获取空间信息，spaceInfo信息为：{}", spaceInfo.toJson());
 
-    /**
+    /*
      * 新建空间
      */
     WxCpSpaceCreateRequest request = new WxCpSpaceCreateRequest();
@@ -269,7 +266,7 @@ public void test() throws Exception {
     log.info("空间id为：{}", spaceCreateData.getSpaceId()); //
     log.info(spaceCreateData.toJson());
 
-    /**
+    /*
      * 重命名空间
      */
     WxCpSpaceRenameRequest wxCpSpaceRenameRequest = new WxCpSpaceRenameRequest();
@@ -279,10 +276,10 @@ public void test() throws Exception {
     WxCpBaseResp baseResp = cpService.getOaWeDriveService().spaceRename(wxCpSpaceRenameRequest);
     log.info("重命名成功：{}", baseResp.toJson());
 
-    /**
+    /*
      * 解散空间
      */
-    WxCpBaseResp thisResp = cpService.getOaWeDriveService().spaceDismiss("WangKai", spaceCreateData.getSpaceId());
+    WxCpBaseResp thisResp = cpService.getOaWeDriveService().spaceDismiss(spaceCreateData.getSpaceId());
     log.info("解散成功：{}", thisResp.toJson());
 
   }
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImplTest.java
index c2b1dad933..6b861cedec 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImplTest.java
@@ -4,7 +4,7 @@
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.error.WxMpErrorMsgEnum;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.cp.api.ApiTestModule;
 import me.chanjar.weixin.cp.api.WxCpService;
@@ -92,7 +92,7 @@ public Object getRequestHttpProxy() {
       }
 
       @Override
-      public HttpType getRequestType() {
+      public HttpClientType getRequestType() {
         return null;
       }
 
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java
index 9f7dd8c531..4bd80928bd 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpExternalContactServiceImplTest.java
@@ -1,7 +1,16 @@
 package me.chanjar.weixin.cp.api.impl;
 
+import static org.testng.Assert.assertNotNull;
+
 import com.google.common.collect.Lists;
 import com.google.inject.Inject;
+
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.XmlUtils;
 import me.chanjar.weixin.cp.api.ApiTestModule;
@@ -10,6 +19,7 @@
 import me.chanjar.weixin.cp.bean.external.*;
 import me.chanjar.weixin.cp.bean.external.contact.WxCpExternalContactBatchInfo;
 import me.chanjar.weixin.cp.bean.external.contact.WxCpExternalContactInfo;
+import me.chanjar.weixin.cp.bean.external.contact.WxCpExternalContactListInfo;
 import me.chanjar.weixin.cp.bean.external.msg.Attachment;
 import me.chanjar.weixin.cp.bean.external.msg.AttachmentBuilder;
 import me.chanjar.weixin.cp.bean.external.msg.Image;
@@ -22,13 +32,6 @@
 import org.testng.annotations.Test;
 import org.testng.collections.CollectionUtils;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-
-import static org.testng.Assert.assertNotNull;
-
 /**
  * The type Wx cp external contact service impl test.
  */
@@ -90,6 +93,20 @@ public void testGetContactWay() throws WxErrorException {
     assertNotNull(contactWayInfo);
   }
 
+  /**
+   * Test list contact way.
+   *
+   * @throws WxErrorException the wx error exception
+   */
+  @Test
+  public void testListContactWay() throws WxErrorException {
+    long startTime = LocalDateTime.now().minusDays(1).toEpochSecond(ZoneOffset.of("+8"));
+    long endTime = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
+    WxCpContactWayList wxCpContactWayList = this.wxCpService.getExternalContactService().listContactWay(startTime, endTime, null, 100L);
+    System.out.println(wxCpContactWayList.toJson());
+    assertNotNull(wxCpContactWayList);
+  }
+
   /**
    * Test update contact way.
    *
@@ -188,6 +205,19 @@ public void testGetContactDetailBatch() throws WxErrorException {
     assertNotNull(result);
   }
 
+  /**
+   * Test get contact list.
+   *
+   * @throws WxErrorException the wx error exception
+   */
+  @Test
+  public void testGetContactList() throws WxErrorException {
+    WxCpExternalContactListInfo result =
+      this.wxCpService.getExternalContactService().getContactList("", 100);
+    System.out.println(result);
+    assertNotNull(result);
+  }
+
   /**
    * Test get corp tag list.
    *
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java
index b964aad513..381a4c1454 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImplTest.java
@@ -7,6 +7,8 @@
 import me.chanjar.weixin.cp.api.ApiTestModule;
 import me.chanjar.weixin.cp.api.TestConstants;
 import me.chanjar.weixin.cp.api.WxCpService;
+import me.chanjar.weixin.cp.bean.media.MediaUploadByUrlReq;
+import me.chanjar.weixin.cp.bean.media.MediaUploadByUrlResult;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
@@ -127,4 +129,38 @@ public void testGetJssdkFile() throws WxErrorException {
     assertThat(file).isNotNull();
     System.out.println(file);
   }
+
+  /**
+   * Test upload media by url.
+   *
+   * @throws WxErrorException the wx error exception
+   */
+  @Test
+  public void testUploadMediaByUrl() throws WxErrorException {
+    MediaUploadByUrlReq req = new MediaUploadByUrlReq();
+    req.setScene(1);
+    req.setType("video");
+    req.setFilename("mov_bbb");
+    req.setUrl("https://www.w3school.com.cn/example/html5/mov_bbb.mp4");
+    req.setMd5("198918f40ecc7cab0fc4231adaf67c96");
+    String jobId = this.wxService.getMediaService().uploadByUrl(req);
+    System.out.println(jobId);
+  }
+
+  /**
+   * Test upload media by url.
+   *
+   * @throws WxErrorException the wx error exception
+   */
+  @Test
+  public void testUploadMediaByUrlResult() throws WxErrorException, InterruptedException {
+    String jobId = "job1745801375_5GIKWuFF3M7hcIkeSNMqs_W26xy5VeSWjLaLFTEdSfQ";
+    MediaUploadByUrlResult result = this.wxService.getMediaService().uploadByUrl(jobId);
+    System.out.println(result);
+  }
+
+  @Test
+  public void testUploadMediaJobFinishEvent() throws WxErrorException {
+    File file = this.wxService.getMediaService().getJssdkFile("....");
+  }
 }
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMessageServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMessageServiceImplTest.java
index 708542f41d..860526bc68 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMessageServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpMessageServiceImplTest.java
@@ -80,6 +80,7 @@ public void testSendMessage() throws WxErrorException {
     System.out.println(messageSendResult.getInvalidPartyList());
     System.out.println(messageSendResult.getInvalidUserList());
     System.out.println(messageSendResult.getInvalidTagList());
+    System.out.println(messageSendResult.getUnlicensedUserList());
   }
 
   /**
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImplTest.java
index a37a42ee68..f722a248d3 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImplTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpOaServiceImplTest.java
@@ -8,6 +8,7 @@
 import me.chanjar.weixin.cp.api.WxCpService;
 import me.chanjar.weixin.cp.bean.WxCpBaseResp;
 import me.chanjar.weixin.cp.bean.oa.*;
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
 import org.apache.commons.lang3.time.DateFormatUtils;
 import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
@@ -162,14 +163,252 @@ public void testGetCheckinOption() throws WxErrorException {
    */
   @Test
   public void testGetCropCheckinOption() throws WxErrorException {
-
-    Date now = new Date();
     List<WxCpCropCheckinOption> results = wxService.getOaService().getCropCheckinOption();
     assertThat(results).isNotNull();
     System.out.println("results ");
     System.out.println(gson.toJson(results));
   }
 
+  /**
+   * Test new ot_info_v2 structure deserialization.
+   */
+  @Test
+  public void testOtInfoV2Deserialization() {
+    // Test JSON with ot_info_v2 structure based on the new API response format
+    String jsonWithOtInfoV2 = "{\n" +
+      "  \"groupid\": 1,\n" +
+      "  \"groupname\": \"test group\",\n" +
+      "  \"grouptype\": 0,\n" +
+      "  \"ot_info_v2\": {\n" +
+      "    \"workdayconf\": {\n" +
+      "      \"allow_ot\": true,\n" +
+      "      \"type\": 1\n" +
+      "    },\n" +
+      "    \"restdayconf\": {\n" +
+      "      \"allow_ot\": false,\n" +
+      "      \"type\": 0\n" +
+      "    },\n" +
+      "    \"holidayconf\": {\n" +
+      "      \"allow_ot\": true,\n" +
+      "      \"type\": 2\n" +
+      "    }\n" +
+      "  }\n" +
+      "}";
+
+    WxCpCropCheckinOption option = WxCpGsonBuilder.create().fromJson(jsonWithOtInfoV2, WxCpCropCheckinOption.class);
+    assertThat(option).isNotNull();
+    assertThat(option.getOtInfoV2()).isNotNull();
+    assertThat(option.getOtInfoV2().getWorkdayConf()).isNotNull();
+    assertThat(option.getOtInfoV2().getWorkdayConf().getAllowOt()).isTrue();
+    assertThat(option.getOtInfoV2().getWorkdayConf().getType()).isEqualTo(1);
+    assertThat(option.getOtInfoV2().getRestdayConf()).isNotNull();
+    assertThat(option.getOtInfoV2().getRestdayConf().getAllowOt()).isFalse();
+    assertThat(option.getOtInfoV2().getHolidayConf().getAllowOt()).isTrue();
+    
+    System.out.println("Parsed ot_info_v2 structure:");
+    System.out.println(gson.toJson(option.getOtInfoV2()));
+  }
+
+  /**
+   * Test late_rule field deserialization in getCropCheckinOption response.
+   */
+  @Test
+  public void testLateRuleDeserialization() {
+    // Test JSON with late_rule structure based on the issue #3323
+    String jsonWithLateRule = "{\n" +
+      "  \"grouptype\": 1,\n" +
+      "  \"groupid\": 1,\n" +
+      "  \"checkindate\": [\n" +
+      "    {\n" +
+      "      \"workdays\": [1, 2, 3, 4, 5],\n" +
+      "      \"checkintime\": [\n" +
+      "        {\n" +
+      "          \"time_id\": 1,\n" +
+      "          \"work_sec\": 32400,\n" +
+      "          \"off_work_sec\": 64800,\n" +
+      "          \"remind_work_sec\": 31800,\n" +
+      "          \"remind_off_work_sec\": 64800,\n" +
+      "          \"rest_begin_time\": 43200,\n" +
+      "          \"rest_end_time\": 48600,\n" +
+      "          \"allow_rest\": true,\n" +
+      "          \"earliest_work_sec\": 21600,\n" +
+      "          \"latest_work_sec\": 64740,\n" +
+      "          \"earliest_off_work_sec\": 32460,\n" +
+      "          \"latest_off_work_sec\": 107940,\n" +
+      "          \"no_need_checkon\": false,\n" +
+      "          \"no_need_checkoff\": false\n" +
+      "        }\n" +
+      "      ],\n" +
+      "      \"noneed_offwork\": false,\n" +
+      "      \"limit_aheadtime\": 0,\n" +
+      "      \"flex_on_duty_time\": 0,\n" +
+      "      \"flex_off_duty_time\": 0,\n" +
+      "      \"allow_flex\": false,\n" +
+      "      \"late_rule\": {\n" +
+      "        \"offwork_after_time\": 3600,\n" +
+      "        \"onwork_flex_time\": 3600,\n" +
+      "        \"allow_offwork_after_time\": true,\n" +
+      "        \"timerules\": [\n" +
+      "          {\n" +
+      "            \"offwork_after_time\": 18000,\n" +
+      "            \"onwork_flex_time\": 3600\n" +
+      "          },\n" +
+      "          {\n" +
+      "            \"offwork_after_time\": 21600,\n" +
+      "            \"onwork_flex_time\": 7200\n" +
+      "          }\n" +
+      "        ]\n" +
+      "      },\n" +
+      "      \"max_allow_arrive_early\": 0,\n" +
+      "      \"max_allow_arrive_late\": 0\n" +
+      "    }\n" +
+      "  ],\n" +
+      "  \"groupname\": \"打卡\",\n" +
+      "  \"need_photo\": false\n" +
+      "}";
+
+    WxCpCropCheckinOption option = WxCpGsonBuilder.create().fromJson(jsonWithLateRule, WxCpCropCheckinOption.class);
+    assertThat(option).isNotNull();
+    assertThat(option.getCheckinDate()).isNotNull();
+    assertThat(option.getCheckinDate().size()).isEqualTo(1);
+    
+    WxCpCheckinGroupBase.CheckinDate checkinDate = option.getCheckinDate().get(0);
+    assertThat(checkinDate).isNotNull();
+    assertThat(checkinDate.getAllowFlex()).isFalse();
+    assertThat(checkinDate.getMaxAllowArriveEarly()).isEqualTo(0);
+    assertThat(checkinDate.getMaxAllowArriveLate()).isEqualTo(0);
+    
+    // Test late_rule field
+    assertThat(checkinDate.getLateRule()).isNotNull();
+    assertThat(checkinDate.getLateRule().getOffWorkAfterTime()).isEqualTo(3600);
+    assertThat(checkinDate.getLateRule().getOnWorkFlexTime()).isEqualTo(3600);
+    assertThat(checkinDate.getLateRule().getAllowOffWorkAfterTime()).isTrue();
+    assertThat(checkinDate.getLateRule().getTimerules()).isNotNull();
+    assertThat(checkinDate.getLateRule().getTimerules().size()).isEqualTo(2);
+    
+    // Test timerules
+    WxCpCheckinGroupBase.TimeRule firstRule = checkinDate.getLateRule().getTimerules().get(0);
+    assertThat(firstRule.getOffWorkAfterTime()).isEqualTo(18000);
+    assertThat(firstRule.getOnWorkFlexTime()).isEqualTo(3600);
+    
+    // Test CheckinTime fields
+    assertThat(checkinDate.getCheckinTime()).isNotNull();
+    assertThat(checkinDate.getCheckinTime().size()).isEqualTo(1);
+    
+    WxCpCheckinGroupBase.CheckinTime checkinTime = checkinDate.getCheckinTime().get(0);
+    assertThat(checkinTime.getTimeId()).isEqualTo(1);
+    assertThat(checkinTime.getRestBeginTime()).isEqualTo(43200);
+    assertThat(checkinTime.getRestEndTime()).isEqualTo(48600);
+    assertThat(checkinTime.getAllowRest()).isTrue();
+    assertThat(checkinTime.getEarliestWorkSec()).isEqualTo(21600);
+    assertThat(checkinTime.getLatestWorkSec()).isEqualTo(64740);
+    assertThat(checkinTime.getEarliestOffWorkSec()).isEqualTo(32460);
+    assertThat(checkinTime.getLatestOffWorkSec()).isEqualTo(107940);
+    assertThat(checkinTime.getNoNeedCheckon()).isFalse();
+    assertThat(checkinTime.getNoNeedCheckoff()).isFalse();
+    
+    System.out.println("Successfully parsed late_rule and new checkintime fields:");
+    System.out.println(gson.toJson(option));
+  }
+
+  /**
+   * Test issue #3323 - full JSON from the issue report.
+   */
+  @Test
+  public void testIssue3323FullJson() {
+    // Full JSON from issue #3323
+    String issueJson = "{\n" +
+      "      \"grouptype\": 1,\n" +
+      "      \"groupid\": 1,\n" +
+      "      \"checkindate\": [\n" +
+      "        {\n" +
+      "          \"workdays\": [\n" +
+      "            1,\n" +
+      "            2,\n" +
+      "            3,\n" +
+      "            4,\n" +
+      "            5\n" +
+      "          ],\n" +
+      "          \"checkintime\": [\n" +
+      "            {\n" +
+      "              \"time_id\": 1,\n" +
+      "              \"work_sec\": 32400,\n" +
+      "              \"off_work_sec\": 64800,\n" +
+      "              \"remind_work_sec\": 31800,\n" +
+      "              \"remind_off_work_sec\": 64800,\n" +
+      "              \"rest_begin_time\": 43200,\n" +
+      "              \"rest_end_time\": 48600,\n" +
+      "              \"allow_rest\": true,\n" +
+      "              \"earliest_work_sec\": 21600,\n" +
+      "              \"latest_work_sec\": 64740,\n" +
+      "              \"earliest_off_work_sec\": 32460,\n" +
+      "              \"latest_off_work_sec\": 107940,\n" +
+      "              \"no_need_checkon\": false,\n" +
+      "              \"no_need_checkoff\": false\n" +
+      "            }\n" +
+      "          ],\n" +
+      "          \"noneed_offwork\": false,\n" +
+      "          \"limit_aheadtime\": 0,\n" +
+      "          \"flex_on_duty_time\": 0,\n" +
+      "          \"flex_off_duty_time\": 0,\n" +
+      "          \"allow_flex\": false,\n" +
+      "          \"late_rule\": {\n" +
+      "            \"offwork_after_time\": 3600,\n" +
+      "            \"onwork_flex_time\": 3600,\n" +
+      "            \"allow_offwork_after_time\": true,\n" +
+      "            \"timerules\": [\n" +
+      "              {\n" +
+      "                \"offwork_after_time\": 18000,\n" +
+      "                \"onwork_flex_time\": 3600\n" +
+      "              },\n" +
+      "              {\n" +
+      "                \"offwork_after_time\": 21600,\n" +
+      "                \"onwork_flex_time\": 7200\n" +
+      "              },\n" +
+      "              {\n" +
+      "                \"offwork_after_time\": 28800,\n" +
+      "                \"onwork_flex_time\": 10800\n" +
+      "              }\n" +
+      "            ]\n" +
+      "          },\n" +
+      "          \"max_allow_arrive_early\": 0,\n" +
+      "          \"max_allow_arrive_late\": 0\n" +
+      "        }\n" +
+      "      ],\n" +
+      "      \"spe_workdays\": [],\n" +
+      "      \"spe_offdays\": [],\n" +
+      "      \"sync_holidays\": true,\n" +
+      "      \"groupname\": \"打卡\",\n" +
+      "      \"need_photo\": false,\n" +
+      "      \"wifimac_infos\": [],\n" +
+      "      \"note_can_use_local_pic\": true,\n" +
+      "      \"allow_checkin_offworkday\": false,\n" +
+      "      \"allow_apply_offworkday\": false,\n" +
+      "      \"loc_infos\": []\n" +
+      "    }";
+
+    WxCpCropCheckinOption option = WxCpGsonBuilder.create().fromJson(issueJson, WxCpCropCheckinOption.class);
+    assertThat(option).isNotNull();
+    assertThat(option.getGroupId()).isEqualTo(1);
+    assertThat(option.getGroupName()).isEqualTo("打卡");
+    assertThat(option.getCheckinDate()).isNotNull();
+    assertThat(option.getCheckinDate().size()).isEqualTo(1);
+    
+    WxCpCheckinGroupBase.CheckinDate checkinDate = option.getCheckinDate().get(0);
+    assertThat(checkinDate.getLateRule()).isNotNull();
+    assertThat(checkinDate.getLateRule().getOffWorkAfterTime()).isEqualTo(3600);
+    assertThat(checkinDate.getLateRule().getOnWorkFlexTime()).isEqualTo(3600);
+    assertThat(checkinDate.getLateRule().getAllowOffWorkAfterTime()).isTrue();
+    assertThat(checkinDate.getLateRule().getTimerules()).isNotNull();
+    assertThat(checkinDate.getLateRule().getTimerules().size()).isEqualTo(3);
+    
+    System.out.println("✓ Successfully parsed full JSON from issue #3323");
+    System.out.println("✓ Late Rule offwork_after_time: " + checkinDate.getLateRule().getOffWorkAfterTime());
+    System.out.println("✓ Late Rule onwork_flex_time: " + checkinDate.getLateRule().getOnWorkFlexTime());
+    System.out.println("✓ Late Rule allow_offwork_after_time: " + checkinDate.getLateRule().getAllowOffWorkAfterTime());
+    System.out.println("✓ Late Rule timerules count: " + checkinDate.getLateRule().getTimerules().size());
+  }
+
   /**
    * Test get approval info.
    *
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpSchoolUserServiceImplTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpSchoolUserServiceImplTest.java
new file mode 100644
index 0000000000..da1cc25542
--- /dev/null
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/impl/WxCpSchoolUserServiceImplTest.java
@@ -0,0 +1,139 @@
+package me.chanjar.weixin.cp.api.impl;
+
+import com.google.gson.Gson;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.cp.api.WxCpService;
+import me.chanjar.weixin.cp.bean.school.user.WxCpDepartmentList;
+import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
+import org.mockito.Mockito;
+import org.testng.annotations.Test;
+
+import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.School.DEPARTMENT_LIST;
+import static org.testng.Assert.assertEquals;
+
+public class WxCpSchoolUserServiceImplTest {
+
+
+  String allDeptListJson = "{\n" +
+    "\t\"errcode\": 0,\n" +
+    "\t\"errmsg\": \"ok\",\n" +
+    "\t\"departments\": [\n" +
+    "\t\t{\n" +
+    "\t\t\t\"name\": \"一年级\",\n" +
+    "\t\t\t\"parentid\": 1,\n" +
+    "\t\t\t\"id\": 2,\n" +
+    "\t\t\t\"type\":2,\n" +
+    "\t\t\t\"register_year\":2018,\n" +
+    "\t\t\t\"standard_grade\":1,\n" +
+    "\t\t\t\"order\":1,\n" +
+    "\t\t\t\"department_admins\": [\n" +
+    "\t\t\t\t{\n" +
+    "\t\t\t\t\t\"userid\": \"zhangsan\",\n" +
+    "\t\t\t\t\t\"type\": 1\n" +
+    "\t\t\t\t},\n" +
+    "\t\t\t\t{\n" +
+    "\t\t\t\t\t\"userid\": \"lisi\",\n" +
+    "\t\t\t\t\t\"type\": 2\n" +
+    "\t\t\t\t}\n" +
+    "\t\t\t],\n" +
+    "            \"is_graduated\": 0\n" +
+    "\t\t},\n" +
+    "\t\t{\n" +
+    "\t\t\t\"name\": \"一年级一班\",\n" +
+    "\t\t\t\"parentid\": 1,\n" +
+    "\t\t\t\"id\": 3,\n" +
+    "\t\t\t\"type\": 1,\n" +
+    "\t\t\t\"department_admins\": [\n" +
+    "\t\t\t\t{\n" +
+    "\t\t\t\t\t\"userid\": \"zhangsan\",\n" +
+    "\t\t\t\t\t\"type\": 3,\n" +
+    "\t\t\t\t\t\"subject\":\"语文\"\n" +
+    "\t\t\t\t},\n" +
+    "\t\t\t\t{\n" +
+    "\t\t\t\t\t\"userid\": \"lisi\",\n" +
+    "\t\t\t\t\t\"type\": 4,\n" +
+    "\t\t\t\t\t\"subject\":\"数学\"\n" +
+    "\t\t\t\t}\n" +
+    "\t\t\t],\n" +
+    "\t\t\t\"open_group_chat\": 1,\n" +
+    "            \"group_chat_id\": \"group_chat_id\"\n" +
+    "\t\t}\n" +
+    "\t]\n" +
+    "}\n";
+
+  String deptId3Json = "{\n" +
+    "  \"errcode\": 0,\n" +
+    "  \"errmsg\": \"ok\",\n" +
+    "  \"departments\": [\n" +
+    "    {\n" +
+    "      \"name\": \"一年级一班\",\n" +
+    "      \"parentid\": 1,\n" +
+    "      \"id\": 3,\n" +
+    "      \"type\": 1,\n" +
+    "      \"department_admins\": [\n" +
+    "        {\n" +
+    "          \"userid\": \"zhangsan\",\n" +
+    "          \"type\": 3,\n" +
+    "          \"subject\":\"语文\"\n" +
+    "        },\n" +
+    "        {\n" +
+    "          \"userid\": \"lisi\",\n" +
+    "          \"type\": 4,\n" +
+    "          \"subject\":\"数学\"\n" +
+    "        }\n" +
+    "      ],\n" +
+    "      \"open_group_chat\": 1,\n" +
+    "      \"group_chat_id\": \"group_chat_id\"\n" +
+    "    }\n" +
+    "  ]\n" +
+    "}";
+
+  String deptId2Json = "{\n" +
+    "  \"errcode\": 0,\n" +
+    "  \"errmsg\": \"ok\",\n" +
+    "  \"departments\": []\n" +
+    "}\n";
+
+
+  @Test
+  public void testListDepartmentWhenIdIsNull() throws WxErrorException {
+
+    WxCpService mockCpService = Mockito.mock(WxCpService.class);
+    WxCpSchoolUserServiceImpl wxCpSchoolUserService = new WxCpSchoolUserServiceImpl(mockCpService);
+    Mockito.when(mockCpService.getWxCpConfigStorage()).thenReturn(new WxCpDefaultConfigImpl());
+    Mockito.when(mockCpService.get(mockCpService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_LIST), null)).thenReturn(allDeptListJson);
+    WxCpDepartmentList wxCpDepartmentList = wxCpSchoolUserService.listDepartment(null);
+    //WxCpDepartmentList没有重写Equals和Hashcode,不能直接比较
+    Gson gson = new Gson();
+    assertEquals(gson.toJson(wxCpDepartmentList), gson.toJson(gson.fromJson(allDeptListJson, WxCpDepartmentList.class)), "should be equal");
+
+  }
+
+  @Test
+  public void testListDepartmentWhenIdIs2() throws WxErrorException {
+
+    WxCpService mockCpService = Mockito.mock(WxCpService.class);
+    WxCpSchoolUserServiceImpl wxCpSchoolUserService = new WxCpSchoolUserServiceImpl(mockCpService);
+    Mockito.when(mockCpService.getWxCpConfigStorage()).thenReturn(new WxCpDefaultConfigImpl());
+    Gson gson = new Gson();
+    int deptId = 2;
+    Mockito.when(mockCpService.get(String.format("%s?id=%s", mockCpService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_LIST), deptId), null)).thenReturn(deptId2Json);
+    //WxCpDepartmentList没有重写Equals和Hashcode,不能直接比较
+    assertEquals(gson.toJson(wxCpSchoolUserService.listDepartment(deptId)), gson.toJson(gson.fromJson(deptId2Json, WxCpDepartmentList.class)), "should be equal");
+
+  }
+
+  @Test
+  public void testListDepartmentWhenIdIs3() throws WxErrorException {
+
+    WxCpService mockCpService = Mockito.mock(WxCpService.class);
+    WxCpSchoolUserServiceImpl wxCpSchoolUserService = new WxCpSchoolUserServiceImpl(mockCpService);
+    Mockito.when(mockCpService.getWxCpConfigStorage()).thenReturn(new WxCpDefaultConfigImpl());
+    Gson gson = new Gson();
+    int deptId = 3;
+    Mockito.when(mockCpService.get(String.format("%s?id=%s", mockCpService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_LIST), deptId), null)).thenReturn(deptId3Json);
+    //WxCpDepartmentList没有重写Equals和Hashcode,不能直接比较
+    assertEquals(gson.toJson(wxCpSchoolUserService.listDepartment(deptId)), gson.toJson(gson.fromJson(deptId3Json, WxCpDepartmentList.class)), "should be equal");
+
+  }
+}
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessageTest.java
index d6cd827630..28246cf00b 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessageTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpTpXmlMessageTest.java
@@ -152,7 +152,7 @@ public void enterAppTest() {
     assertEquals(wxXmlMessage.getCreateTime(), Long.valueOf(1408091189));
     assertEquals(wxXmlMessage.getEvent(), "enter_agent");
     assertEquals(wxXmlMessage.getEventKey(), "");
-    assertEquals(wxXmlMessage.getAgentID(), Integer.valueOf(1));
+    assertEquals(wxXmlMessage.getAgentID(), 1);
   }
 
   /**
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessageTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessageTest.java
index a760a17ff6..5bcfe9698a 100644
--- a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessageTest.java
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/message/WxCpXmlMessageTest.java
@@ -6,6 +6,7 @@
 import org.testng.annotations.Test;
 
 import static me.chanjar.weixin.cp.constant.WxCpConsts.EventType.TASKCARD_CLICK;
+import static me.chanjar.weixin.cp.constant.WxCpConsts.EventType.UPLOAD_MEDIA_JOB_FINISH;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
@@ -421,4 +422,24 @@ public void testOpenApprovalChange() {
     assertThat(wxCpXmlMessage.getApprovalInfo().getApprovalNodes().get(0).getItems().get(0).getItemName()).isNotEmpty();
     assertThat(wxCpXmlMessage.getApprovalInfo().getNotifyNodes().get(0).getItemName()).isNotEmpty();
   }
+
+  /**
+   * Test open approval change.
+   */
+  public void testUploadMediaJobFinishEvent() {
+    String xml = "<xml>\n" +
+      "\t<ToUserName><![CDATA[wx28dbb14e3720FAKE]]></ToUserName>\n" +
+      "\t<FromUserName><![CDATA[sys]]></FromUserName>\n" +
+      "\t<CreateTime>1425284517</CreateTime>\n" +
+      "\t<MsgType><![CDATA[event]]></MsgType>\n" +
+      "\t<Event><![CDATA[upload_media_job_finish]]></Event>\n" +
+      "\t<JobId><![CDATA[jobid_S0MrnndvRG5fadSlLwiBqiDDbM143UqTmKP3152FZk4]]></JobId>\n" +
+      "</xml>";
+
+    WxCpXmlMessage wxCpXmlMessage = WxCpXmlMessage.fromXml(xml);
+    assertThat(wxCpXmlMessage).isNotNull();
+    assertThat(wxCpXmlMessage.getJobId()).isNotEmpty();
+    assertThat(wxCpXmlMessage.getJobId()).isEqualTo("jobid_S0MrnndvRG5fadSlLwiBqiDDbM143UqTmKP3152FZk4");
+    assertThat(wxCpXmlMessage.getEvent()).isEqualTo(UPLOAD_MEDIA_JOB_FINISH);
+  }
 }
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApprovalTemplateResultTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApprovalTemplateResultTest.java
new file mode 100644
index 0000000000..db79a06b32
--- /dev/null
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/bean/oa/WxCpOaApprovalTemplateResultTest.java
@@ -0,0 +1,390 @@
+package me.chanjar.weixin.cp.bean.oa;
+
+import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.*;
+
+public class WxCpOaApprovalTemplateResultTest {
+
+  @Test
+  public void testFromJson() {
+    String json = "{\n"
+      + "  \"errcode\": 0,\n"
+      + "  \"errmsg\": \"ok\",\n"
+      + "  \"template_names\": [\n"
+      + "    {\n"
+      + "      \"text\": \"智能印章\",\n"
+      + "      \"lang\": \"zh_CN\"\n"
+      + "    },\n"
+      + "    {\n"
+      + "      \"text\": \"Company Seal\",\n"
+      + "      \"lang\": \"en\"\n"
+      + "    }\n"
+      + "  ],\n"
+      + "  \"template_content\": {\n"
+      + "    \"controls\": [\n"
+      + "      {\n"
+      + "        \"property\": {\n"
+      + "          \"control\": \"Text\",\n"
+      + "          \"id\": \"Text-1747127819114\",\n"
+      + "          \"title\": [\n"
+      + "            {\n"
+      + "              \"text\": \"用印事由\",\n"
+      + "              \"lang\": \"zh_CN\"\n"
+      + "            }\n"
+      + "          ],\n"
+      + "          \"placeholder\": [\n"
+      + "            {\n"
+      + "              \"text\": \"\",\n"
+      + "              \"lang\": \"zh_CN\"\n"
+      + "            }\n"
+      + "          ],\n"
+      + "          \"require\": 1,\n"
+      + "          \"un_print\": 0,\n"
+      + "          \"inner_id\": \"\",\n"
+      + "          \"un_replace\": 0,\n"
+      + "          \"display\": 1\n"
+      + "        }\n"
+      + "      },\n"
+      + "      {\n"
+      + "        \"property\": {\n"
+      + "          \"control\": \"Selector\",\n"
+      + "          \"id\": \"Selector-1747123508806\",\n"
+      + "          \"title\": [\n"
+      + "            {\n"
+      + "              \"text\": \"用印类型\",\n"
+      + "              \"lang\": \"zh_CN\"\n"
+      + "            }\n"
+      + "          ],\n"
+      + "          \"placeholder\": [\n"
+      + "            {\n"
+      + "              \"text\": \"\",\n"
+      + "              \"lang\": \"zh_CN\"\n"
+      + "            }\n"
+      + "          ],\n"
+      + "          \"require\": 1,\n"
+      + "          \"un_print\": 0,\n"
+      + "          \"inner_id\": \"\",\n"
+      + "          \"un_replace\": 0,\n"
+      + "          \"display\": 1\n"
+      + "        },\n"
+      + "        \"config\": {\n"
+      + "          \"selector\": {\n"
+      + "            \"type\": \"single\",\n"
+      + "            \"options\": [\n"
+      + "              {\n"
+      + "                \"key\": \"option-1747123508806\",\n"
+      + "                \"value\": [\n"
+      + "                  {\n"
+      + "                    \"text\": \"一般事务性用印\",\n"
+      + "                    \"lang\": \"zh_CN\"\n"
+      + "                  }\n"
+      + "                ]\n"
+      + "              },\n"
+      + "              {\n"
+      + "                \"key\": \"option-1747123508807\",\n"
+      + "                \"value\": [\n"
+      + "                  {\n"
+      + "                    \"text\": \"对外事务性用印\",\n"
+      + "                    \"lang\": \"zh_CN\"\n"
+      + "                  }\n"
+      + "                ]\n"
+      + "              },\n"
+      + "              {\n"
+      + "                \"key\": \"option-1747123530814\",\n"
+      + "                \"value\": [\n"
+      + "                  {\n"
+      + "                    \"text\": \"重大事务性用印\",\n"
+      + "                    \"lang\": \"zh_CN\"\n"
+      + "                  }\n"
+      + "                ]\n"
+      + "              }\n"
+      + "            ],\n"
+      + "            \"op_relations\": [],\n"
+      + "            \"external_option\": {\n"
+      + "              \"use_external_option\": false,\n"
+      + "              \"external_url\": \"\"\n"
+      + "            }\n"
+      + "          }\n"
+      + "        }\n"
+      + "      },\n"
+      + "      {\n"
+      + "        \"property\": {\n"
+      + "          \"control\": \"Tips\",\n"
+      + "          \"id\": \"Tips-1747123397470\",\n"
+      + "          \"title\": [\n"
+      + "            {\n"
+      + "              \"text\": \"说明\",\n"
+      + "              \"lang\": \"zh_CN\"\n"
+      + "            }\n"
+      + "          ],\n"
+      + "          \"placeholder\": [],\n"
+      + "          \"require\": 0,\n"
+      + "          \"un_print\": 0,\n"
+      + "          \"inner_id\": \"\",\n"
+      + "          \"un_replace\": 0,\n"
+      + "          \"display\": 1\n"
+      + "        },\n"
+      + "        \"config\": {\n"
+      + "          \"tips\": {\n"
+      + "            \"tips_content\": [\n"
+      + "              {\n"
+      + "                \"text\": {\n"
+      + "                  \"sub_text\": [\n"
+      + "                    {\n"
+      + "                      \"type\": 1,\n"
+      + "                      \"content\": {\n"
+      + "                        \"plain_text\": {\n"
+      + "                          \"content\": \"用印类型说明：1. 一般事务性用印：内部日常材料流转、常规业务报表报送、非对外承诺性质的证明文件，用印文件内容不得涉及经济、法律责任条款 \"\n"
+      + "                        }\n"
+      + "                      }\n"
+      + "                    }\n"
+      + "                  ]\n"
+      + "                },\n"
+      + "                \"lang\": \"zh_CN\"\n"
+      + "              }\n"
+      + "            ]\n"
+      + "          }\n"
+      + "        }\n"
+      + "      },\n"
+      + "      {\n"
+      + "        \"property\": {\n"
+      + "          \"control\": \"Table\",\n"
+      + "          \"id\": \"Table-1746005041962\",\n"
+      + "          \"title\": [\n"
+      + "            {\n"
+      + "              \"text\": \"印章明细\",\n"
+      + "              \"lang\": \"zh_CN\"\n"
+      + "            }\n"
+      + "          ],\n"
+      + "          \"placeholder\": [\n"
+      + "            {\n"
+      + "              \"text\": \"\",\n"
+      + "              \"lang\": \"zh_CN\"\n"
+      + "            }\n"
+      + "          ],\n"
+      + "          \"require\": 0,\n"
+      + "          \"un_print\": 0,\n"
+      + "          \"inner_id\": \"\",\n"
+      + "          \"un_replace\": 0,\n"
+      + "          \"display\": 1\n"
+      + "        },\n"
+      + "        \"config\": {\n"
+      + "          \"table\": {\n"
+      + "            \"children\": [\n"
+      + "              {\n"
+      + "                \"property\": {\n"
+      + "                  \"control\": \"Text\",\n"
+      + "                  \"id\": \"Text-1747127691499\",\n"
+      + "                  \"title\": [\n"
+      + "                    {\n"
+      + "                      \"text\": \"印章名称\",\n"
+      + "                      \"lang\": \"zh_CN\"\n"
+      + "                    }\n"
+      + "                  ],\n"
+      + "                  \"placeholder\": [\n"
+      + "                    {\n"
+      + "                      \"text\": \"请输入“公章”\",\n"
+      + "                      \"lang\": \"zh_CN\"\n"
+      + "                    }\n"
+      + "                  ],\n"
+      + "                  \"require\": 1,\n"
+      + "                  \"un_print\": 0,\n"
+      + "                  \"un_replace\": 0,\n"
+      + "                  \"display\": 1\n"
+      + "                }\n"
+      + "              },\n"
+      + "              {\n"
+      + "                \"property\": {\n"
+      + "                  \"control\": \"Number\",\n"
+      + "                  \"id\": \"Number-1746006598992\",\n"
+      + "                  \"title\": [\n"
+      + "                    {\n"
+      + "                      \"text\": \"普通用印\",\n"
+      + "                      \"lang\": \"zh_CN\"\n"
+      + "                    }\n"
+      + "                  ],\n"
+      + "                  \"placeholder\": [\n"
+      + "                    {\n"
+      + "                      \"text\": \"请填写正文用印次数\",\n"
+      + "                      \"lang\": \"zh_CN\"\n"
+      + "                    }\n"
+      + "                  ],\n"
+      + "                  \"require\": 1,\n"
+      + "                  \"un_print\": 0,\n"
+      + "                  \"un_replace\": 0,\n"
+      + "                  \"display\": 1\n"
+      + "                }\n"
+      + "              },\n"
+      + "              {\n"
+      + "                \"property\": {\n"
+      + "                  \"control\": \"Number\",\n"
+      + "                  \"id\": \"Number-1746006601002\",\n"
+      + "                  \"title\": [\n"
+      + "                    {\n"
+      + "                      \"text\": \"骑缝用印\",\n"
+      + "                      \"lang\": \"zh_CN\"\n"
+      + "                    }\n"
+      + "                  ],\n"
+      + "                  \"placeholder\": [\n"
+      + "                    {\n"
+      + "                      \"text\": \"请填写骑缝用印次数\",\n"
+      + "                      \"lang\": \"zh_CN\"\n"
+      + "                    }\n"
+      + "                  ],\n"
+      + "                  \"require\": 1,\n"
+      + "                  \"un_print\": 0,\n"
+      + "                  \"un_replace\": 0,\n"
+      + "                  \"display\": 1\n"
+      + "                }\n"
+      + "              },\n"
+      + "              {\n"
+      + "                \"property\": {\n"
+      + "                  \"control\": \"Selector\",\n"
+      + "                  \"id\": \"Selector-1746005136537\",\n"
+      + "                  \"title\": [\n"
+      + "                    {\n"
+      + "                      \"text\": \"是否外借\",\n"
+      + "                      \"lang\": \"zh_CN\"\n"
+      + "                    }\n"
+      + "                  ],\n"
+      + "                  \"placeholder\": [\n"
+      + "                    {\n"
+      + "                      \"text\": \"\",\n"
+      + "                      \"lang\": \"zh_CN\"\n"
+      + "                    }\n"
+      + "                  ],\n"
+      + "                  \"require\": 0,\n"
+      + "                  \"un_print\": 0,\n"
+      + "                  \"un_replace\": 0,\n"
+      + "                  \"display\": 1\n"
+      + "                },\n"
+      + "                \"config\": {\n"
+      + "                  \"selector\": {\n"
+      + "                    \"type\": \"single\",\n"
+      + "                    \"exp_type\": 0,\n"
+      + "                    \"options\": [\n"
+      + "                      {\n"
+      + "                        \"key\": \"option-1746005136537\",\n"
+      + "                        \"value\": [\n"
+      + "                          {\n"
+      + "                            \"text\": \"是\",\n"
+      + "                            \"lang\": \"zh_CN\"\n"
+      + "                          }\n"
+      + "                        ]\n"
+      + "                      },\n"
+      + "                      {\n"
+      + "                        \"key\": \"option-1746005136538\",\n"
+      + "                        \"value\": [\n"
+      + "                          {\n"
+      + "                            \"text\": \"否\",\n"
+      + "                            \"lang\": \"zh_CN\"\n"
+      + "                          }\n"
+      + "                        ]\n"
+      + "                      }\n"
+      + "                    ],\n"
+      + "                    \"op_relations\": [],\n"
+      + "                    \"external_option\": {\n"
+      + "                      \"use_external_option\": false,\n"
+      + "                      \"external_url\": \"\"\n"
+      + "                    }\n"
+      + "                  }\n"
+      + "                }\n"
+      + "              },\n"
+      + "              {\n"
+      + "                \"property\": {\n"
+      + "                  \"control\": \"Date\",\n"
+      + "                  \"id\": \"Date-1746005165574\",\n"
+      + "                  \"title\": [\n"
+      + "                    {\n"
+      + "                      \"text\": \"外借开始时间\",\n"
+      + "                      \"lang\": \"zh_CN\"\n"
+      + "                    }\n"
+      + "                  ],\n"
+      + "                  \"placeholder\": [\n"
+      + "                    {\n"
+      + "                      \"text\": \"\",\n"
+      + "                      \"lang\": \"zh_CN\"\n"
+      + "                    }\n"
+      + "                  ],\n"
+      + "                  \"require\": 0,\n"
+      + "                  \"un_print\": 0,\n"
+      + "                  \"un_replace\": 0,\n"
+      + "                  \"display\": 1\n"
+      + "                },\n"
+      + "                \"config\": {\n"
+      + "                  \"date\": {\n"
+      + "                    \"type\": \"day\"\n"
+      + "                  }\n"
+      + "                }\n"
+      + "              },\n"
+      + "              {\n"
+      + "                \"property\": {\n"
+      + "                  \"control\": \"Date\",\n"
+      + "                  \"id\": \"Date-1746005173386\",\n"
+      + "                  \"title\": [\n"
+      + "                    {\n"
+      + "                      \"text\": \"外借结束时间\",\n"
+      + "                      \"lang\": \"zh_CN\"\n"
+      + "                    }\n"
+      + "                  ],\n"
+      + "                  \"placeholder\": [\n"
+      + "                    {\n"
+      + "                      \"text\": \"\",\n"
+      + "                      \"lang\": \"zh_CN\"\n"
+      + "                    }\n"
+      + "                  ],\n"
+      + "                  \"require\": 0,\n"
+      + "                  \"un_print\": 0,\n"
+      + "                  \"un_replace\": 0,\n"
+      + "                  \"display\": 1\n"
+      + "                },\n"
+      + "                \"config\": {\n"
+      + "                  \"date\": {\n"
+      + "                    \"type\": \"day\"\n"
+      + "                  }\n"
+      + "                }\n"
+      + "              }\n"
+      + "            ],\n"
+      + "            \"stat_field\": [],\n"
+      + "            \"sum_field\": [],\n"
+      + "            \"print_format\": 0\n"
+      + "          }\n"
+      + "        }\n"
+      + "      },\n"
+      + "      {\n"
+      + "        \"property\": {\n"
+      + "          \"control\": \"File\",\n"
+      + "          \"id\": \"item-1494250388062\",\n"
+      + "          \"title\": [\n"
+      + "            {\n"
+      + "              \"text\": \"用印文件\",\n"
+      + "              \"lang\": \"zh_CN\"\n"
+      + "            },\n"
+      + "            {\n"
+      + "              \"text\": \"Attachment\",\n"
+      + "              \"lang\": \"en\"\n"
+      + "            }\n"
+      + "          ],\n"
+      + "          \"placeholder\": [\n"
+      + "            {\n"
+      + "              \"text\": \"\",\n"
+      + "              \"lang\": \"zh_CN\"\n"
+      + "            }\n"
+      + "          ],\n"
+      + "          \"require\": 1,\n"
+      + "          \"un_print\": 0,\n"
+      + "          \"inner_id\": \"\",\n"
+      + "          \"un_replace\": 0,\n"
+      + "          \"display\": 1\n"
+      + "        }\n"
+      + "      }\n"
+      + "    ]\n"
+      + "  }\n"
+      + "}";
+
+    WxCpOaApprovalTemplateResult templateDetail = WxCpGsonBuilder.create().fromJson(json, WxCpOaApprovalTemplateResult.class);
+    System.out.println(templateDetail);
+  }
+}
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/config/impl/DemoToStringFix.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/config/impl/DemoToStringFix.java
new file mode 100644
index 0000000000..48fe9a6639
--- /dev/null
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/config/impl/DemoToStringFix.java
@@ -0,0 +1,66 @@
+package me.chanjar.weixin.cp.config.impl;
+
+import me.chanjar.weixin.common.redis.WxRedisOps;
+
+/**
+ * Demonstration of the fix for toString() StackOverflowError issue
+ */
+public class DemoToStringFix {
+    
+    public static void main(String[] args) {
+        System.out.println("=== Demonstrating toString() Fix for WxCp Redis Config ===");
+        
+        // Create a simple stub WxRedisOps implementation for testing
+        WxRedisOps stubRedisOps = new WxRedisOps() {
+            @Override
+            public String getValue(String key) { return null; }
+            @Override
+            public void setValue(String key, String value, int expire, java.util.concurrent.TimeUnit timeUnit) {}
+            @Override
+            public Long getExpire(String key) { return null; }
+            @Override
+            public void expire(String key, int expire, java.util.concurrent.TimeUnit timeUnit) {}
+            @Override
+            public java.util.concurrent.locks.Lock getLock(String key) { return null; }
+        };
+        
+        // Test AbstractWxCpInRedisConfigImpl directly with our stub
+        AbstractWxCpInRedisConfigImpl config = new AbstractWxCpInRedisConfigImpl(stubRedisOps, "demo:") {
+            // Anonymous class to test the abstract parent
+        };
+        
+        config.setCorpId("demoCorpId");
+        config.setAgentId(1001);
+        
+        System.out.println("Testing toString() method:");
+        try {
+            String result = config.toString();
+            System.out.println("✓ Success! toString() returned: " + result);
+            System.out.println("✓ No StackOverflowError occurred");
+            
+            // Verify the result contains expected information and excludes redisOps
+            boolean containsCorpId = result.contains("demoCorpId");
+            boolean containsAgentId = result.contains("1001");
+            boolean containsKeyPrefix = result.contains("demo:");
+            boolean excludesRedisOps = !result.contains("redisOps") && !result.contains("WxRedisOps");
+            
+            System.out.println("✓ Contains corpId: " + containsCorpId);
+            System.out.println("✓ Contains agentId: " + containsAgentId);
+            System.out.println("✓ Contains keyPrefix: " + containsKeyPrefix);
+            System.out.println("✓ Excludes redisOps: " + excludesRedisOps);
+            
+            if (containsCorpId && containsAgentId && containsKeyPrefix && excludesRedisOps) {
+                System.out.println("✓ All validations passed!");
+            } else {
+                System.out.println("✗ Some validations failed");
+            }
+            
+        } catch (StackOverflowError e) {
+            System.out.println("✗ StackOverflowError still occurred - fix failed");
+        } catch (Exception e) {
+            System.out.println("✗ Unexpected error: " + e.getMessage());
+        }
+        
+        System.out.println("\n=== Demo completed ===");
+    }
+}
\ No newline at end of file
diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml
index af3b2a7c45..60f462e367 100644
--- a/weixin-java-miniapp/pom.xml
+++ b/weixin-java-miniapp/pom.xml
@@ -7,7 +7,7 @@
   <parent>
     <groupId>com.github.binarywang</groupId>
     <artifactId>wx-java</artifactId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
 
   <artifactId>weixin-java-miniapp</artifactId>
@@ -31,6 +31,11 @@
       <artifactId>okhttp</artifactId>
       <scope>provided</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.httpcomponents.client5</groupId>
+      <artifactId>httpclient5</artifactId>
+      <scope>provided</scope>
+    </dependency>
 
     <dependency>
       <groupId>org.testng</groupId>
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaAnalysisService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaAnalysisService.java
index fa6d444406..d6d13431d5 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaAnalysisService.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaAnalysisService.java
@@ -7,7 +7,7 @@
 import java.util.List;
 
 /**
- * 小程序数据分析相关接口
+ * 小程序数据分析相关接口。
  * 文档：https://mp.weixin.qq.com/debug/wxadoc/dev/api/analysis.html
  *
  * @author <a href="https://github.com/charmingoh">Charming</a>
@@ -16,114 +16,114 @@
 public interface WxMaAnalysisService {
 
   /**
-   * 查询概况趋势
+   * 查询概况趋势。
    * 温馨提示：小程序接口目前只能查询一天的数据，即 beginDate 和 endDate 一样
    *
-   * @param beginDate 开始日期
-   * @param endDate   结束日期，限定查询1天数据，end_date允许设置的最大值为昨日
-   * @return 概况趋势
+   * @param beginDate        开始日期
+   * @param endDate          结束日期，限定查询1天数据，end_date允许设置的最大值为昨日
+   * @return                 概况趋势列表
    * @throws WxErrorException 获取失败时抛出，具体错误码请看文档
    */
   List<WxMaSummaryTrend> getDailySummaryTrend(Date beginDate, Date endDate) throws WxErrorException;
 
   /**
-   * 获取日访问趋势
+   * 获取日访问趋势。
    * 温馨提示：小程序接口目前只能查询一天的数据，即 beginDate 和 endDate 一样
    *
-   * @param beginDate 开始日期
-   * @param endDate   结束日期，限定查询1天数据，end_date允许设置的最大值为昨日
-   * @return 日访问趋势
+   * @param beginDate        开始日期
+   * @param endDate          结束日期，限定查询1天数据，end_date允许设置的最大值为昨日
+   * @return                 日访问趋势列表
    * @throws WxErrorException 获取失败时抛出，具体错误码请看文档
    */
   List<WxMaVisitTrend> getDailyVisitTrend(Date beginDate, Date endDate) throws WxErrorException;
 
   /**
-   * 获取周访问趋势
+   * 获取周访问趋势。
    * 限定查询一个自然周的数据，时间必须按照自然周的方式输入： 如：20170306(周一), 20170312(周日)
    *
-   * @param beginDate 开始日期，为周一日期
-   * @param endDate   结束日期，为周日日期，限定查询一周数据
-   * @return 周访问趋势（每项数据都是一个自然周汇总）
+   * @param beginDate        开始日期，为周一日期
+   * @param endDate          结束日期，为周日日期，限定查询一周数据
+   * @return                 周访问趋势列表（每项数据都是一个自然周汇总）
    * @throws WxErrorException 获取失败时抛出，具体错误码请看文档
    */
   List<WxMaVisitTrend> getWeeklyVisitTrend(Date beginDate, Date endDate) throws WxErrorException;
 
   /**
-   * 获取月访问趋势
+   * 获取月访问趋势。
    * 限定查询一个自然月的数据，时间必须按照自然月的方式输入： 如：20170201(月初), 20170228(月末)
    *
-   * @param beginDate 开始日期，为自然月第一天
-   * @param endDate   结束日期，为自然月最后一天，限定查询一个月数据
-   * @return 月访问趋势（每项数据都是一个自然月汇总）
+   * @param beginDate        开始日期，为自然月第一天
+   * @param endDate          结束日期，为自然月最后一天，限定查询一个月数据
+   * @return                 月访问趋势列表（每项数据都是一个自然月汇总）
    * @throws WxErrorException 获取失败时抛出，具体错误码请看文档
    */
   List<WxMaVisitTrend> getMonthlyVisitTrend(Date beginDate, Date endDate) throws WxErrorException;
 
   /**
-   * 获取访问分布
+   * 获取访问分布。
    * （此接口目前只能查询一天的数据，即 beginDate 和 endDate 一样）
    *
-   * @param beginDate 开始日期，为周一日期
-   * @param endDate   结束日期，限定查询1天数据，end_date允许设置的最大值为昨日
-   * @return 访问分布
+   * @param beginDate        开始日期
+   * @param endDate          结束日期，限定查询1天数据，end_date允许设置的最大值为昨日
+   * @return                 访问分布对象
    * @throws WxErrorException 获取失败时抛出，具体错误码请看文档
    */
   WxMaVisitDistribution getVisitDistribution(Date beginDate, Date endDate) throws WxErrorException;
 
   /**
-   * 日留存
+   * 获取日留存数据。
    * （此接口目前只能查询一天的数据，即 beginDate 和 endDate 一样）
    *
-   * @param beginDate 开始日期，为周一日期
-   * @param endDate   结束日期，限定查询 1 天数据，endDate 允许设置的最大值为昨日
-   * @return 日留存
+   * @param beginDate        开始日期
+   * @param endDate          结束日期，限定查询 1 天数据，endDate 允许设置的最大值为昨日
+   * @return                 日留存信息对象
    * @throws WxErrorException 获取失败时抛出，具体错误码请看文档
    */
   WxMaRetainInfo getDailyRetainInfo(Date beginDate, Date endDate) throws WxErrorException;
 
   /**
-   * 周留存
+   * 获取周留存数据。
    * 限定查询一个自然周的数据，时间必须按照自然周的方式输入： 如：20170306(周一), 20170312(周日)
    *
-   * @param beginDate 开始日期，为周一日期
-   * @param endDate   结束日期，为周日日期，限定查询一周数据
-   * @return 周留存
+   * @param beginDate        开始日期，为周一日期
+   * @param endDate          结束日期，为周日日期，限定查询一周数据
+   * @return                 周留存信息对象
    * @throws WxErrorException 获取失败时抛出，具体错误码请看文档
    */
   WxMaRetainInfo getWeeklyRetainInfo(Date beginDate, Date endDate) throws WxErrorException;
 
   /**
-   * 月留存
+   * 获取月留存数据。
    * 限定查询一个自然月的数据，时间必须按照自然月的方式输入： 如：20170201(月初), 20170228(月末)
    *
-   * @param beginDate 开始日期，为自然月第一天
-   * @param endDate   结束日期，为自然月最后一天，限定查询一个月数据
-   * @return 月留存
+   * @param beginDate        开始日期，为自然月第一天
+   * @param endDate          结束日期，为自然月最后一天，限定查询一个月数据
+   * @return                 月留存信息对象
    * @throws WxErrorException 获取失败时抛出，具体错误码请看文档
    */
   WxMaRetainInfo getMonthlyRetainInfo(Date beginDate, Date endDate) throws WxErrorException;
 
   /**
-   * 获取访问页面数据
+   * 获取访问页面数据。
    * 温馨提示：此接口目前只能查询一天的数据，即 beginDate 和 endDate 一样
    *
-   * @param beginDate 开始日期
-   * @param endDate   结束日期，限定查询1天数据，end_date允许设置的最大值为昨日
-   * @return 访问页面数据
+   * @param beginDate        开始日期
+   * @param endDate          结束日期，限定查询1天数据，end_date允许设置的最大值为昨日
+   * @return                 访问页面数据列表
    * @throws WxErrorException 获取失败时抛出，具体错误码请看文档
    */
   List<WxMaVisitPage> getVisitPage(Date beginDate, Date endDate) throws WxErrorException;
 
   /**
-   * 获取小程序新增或活跃用户的画像分布数据
+   * 获取小程序新增或活跃用户的画像分布数据。
    * 时间范围支持昨天、最近7天、最近30天。
    * 其中，新增用户数为时间范围内首次访问小程序的去重用户数，
    * 活跃用户数为时间范围内访问过小程序的去重用户数。
    * 画像属性包括用户年龄、性别、省份、城市、终端类型、机型。
    *
-   * @param beginDate 开始日期
-   * @param endDate   结束日期，开始日期与结束日期相差的天数限定为0/6/29，分别表示查询最近1/7/30天数据，end_date允许设置的最大值为昨日
-   * @return 小程序新增或活跃用户的画像分布数据
+   * @param beginDate        开始日期
+   * @param endDate          结束日期，开始日期与结束日期相差的天数限定为0/6/29，分别表示查询最近1/7/30天数据，end_date允许设置的最大值为昨日
+   * @return                 小程序新增或活跃用户的画像分布数据对象
    * @throws WxErrorException 获取失败时抛出，具体错误码请看文档
    */
   WxMaUserPortrait getUserPortrait(Date beginDate, Date endDate) throws WxErrorException;
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaCloudService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaCloudService.java
index 4e18fec5c4..ea7e9ab20f 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaCloudService.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaCloudService.java
@@ -16,539 +16,457 @@
  */
 public interface WxMaCloudService {
   /**
-   * Invoke cloud function string.
+   * 触发云函数。注意：HTTP API 途径触发云函数不包含用户信息。
    *
-   * @param name the name
-   * @param body the body
-   * @return the string
-   * @throws WxErrorException the wx error exception
+   * @param name             云函数名称
+   * @param body             云函数的传入参数，具体结构由开发者定义
+   * @return                 云函数返回的buffer
+   * @throws WxErrorException 调用失败时抛出
    */
   String invokeCloudFunction(String name, String body) throws WxErrorException;
 
   /**
-   * <pre>
    * 触发云函数。注意：HTTP API 途径触发云函数不包含用户信息。
    * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/functions/invokeCloudFunction.html
    *
-   * 请求地址
-   * POST https://api.weixin.qq.com/tcb/invokecloudfunction?access_token=ACCESS_TOKEN&env=ENV&name=FUNCTION_NAME
-   *
-   * </pre>
-   *
-   * @param env  string		是	云开发环境ID
-   * @param name string		是	云函数名称
-   * @param body string		是	云函数的传入参数，具体结构由开发者定义。
-   * @return resp_data string	云函数返回的buffer
-   * @throws WxErrorException .
+   * @param env              云开发环境ID
+   * @param name             云函数名称
+   * @param body             云函数的传入参数，具体结构由开发者定义
+   * @return                 云函数返回的buffer
+   * @throws WxErrorException 调用失败时抛出
    */
   String invokeCloudFunction(String env, String name, String body) throws WxErrorException;
 
   /**
-   * Add list.
+   * 批量添加记录到集合。
    *
-   * @param collection the collection
-   * @param list       the list
-   * @return the list
-   * @throws WxErrorException the wx error exception
+   * @param collection       集合名称
+   * @param list             要添加的记录列表
+   * @return                 插入成功的记录ID列表
+   * @throws WxErrorException 添加失败时抛出
    */
-  List<String> add(String collection, List list) throws WxErrorException;
+  List<String> add(String collection, List<?> list) throws WxErrorException;
 
   /**
-   * Add string.
+   * 添加单条记录到集合。
    *
-   * @param collection the collection
-   * @param obj        the obj
-   * @return the string
-   * @throws WxErrorException the wx error exception
+   * @param collection       集合名称
+   * @param obj              要添加的记录对象
+   * @return                 插入成功的记录ID
+   * @throws WxErrorException 添加失败时抛出
    */
   String add(String collection, Object obj) throws WxErrorException;
 
   /**
-   * Database add json array.
+   * 数据库插入记录。
    *
-   * @param query the query
-   * @return the json array
-   * @throws WxErrorException the wx error exception
+   * @param query            数据库操作语句
+   * @return                 插入成功的数据集合主键_id列表
+   * @throws WxErrorException 插入失败时抛出
    */
   JsonArray databaseAdd(String query) throws WxErrorException;
 
   /**
-   * <pre>
-   * 数据库插入记录
-   *
+   * 数据库插入记录。
    * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseAdd.html
-   * 请求地址：POST https://api.weixin.qq.com/tcb/databaseadd?access_token=ACCESS_TOKEN
-   * </pre>
    *
-   * @param env   云环境ID
-   * @param query 数据库操作语句
-   * @return 插入成功的数据集合主键_id json array
-   * @throws WxErrorException .
+   * @param env              云环境ID
+   * @param query            数据库操作语句
+   * @return                 插入成功的数据集合主键_id列表
+   * @throws WxErrorException 插入失败时抛出
    */
   JsonArray databaseAdd(String env, String query) throws WxErrorException;
 
   /**
-   * Delete integer.
+   * 删除集合中符合条件的记录。
    *
-   * @param collection the collection
-   * @param whereJson  the where json
-   * @return the integer
-   * @throws WxErrorException the wx error exception
+   * @param collection       集合名称
+   * @param whereJson        查询条件JSON字符串
+   * @return                 删除的记录数量
+   * @throws WxErrorException 删除失败时抛出
    */
   Integer delete(String collection, String whereJson) throws WxErrorException;
 
   /**
-   * Database delete int.
+   * 数据库删除记录。
    *
-   * @param query the query
-   * @return the int
-   * @throws WxErrorException the wx error exception
+   * @param query            数据库操作语句
+   * @return                 删除记录数量
+   * @throws WxErrorException 删除失败时抛出
    */
   int databaseDelete(String query) throws WxErrorException;
 
   /**
-   * <pre>
-   * 数据库删除记录
-   *
+   * 数据库删除记录。
    * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseDelete.html
-   * 请求地址：POST https://api.weixin.qq.com/tcb/databasedelete?access_token=ACCESS_TOKEN
-   * </pre>
    *
-   * @param env   云环境ID
-   * @param query 数据库操作语句
-   * @return 删除记录数量 int
-   * @throws WxErrorException .
+   * @param env              云环境ID
+   * @param query            数据库操作语句
+   * @return                 删除记录数量
+   * @throws WxErrorException 删除失败时抛出
    */
   int databaseDelete(String env, String query) throws WxErrorException;
 
   /**
-   * Update wx cloud database update result.
+   * 更新集合中符合条件的记录。
    *
-   * @param collection the collection
-   * @param whereJson  the where json
-   * @param updateJson the update json
-   * @return the wx cloud database update result
-   * @throws WxErrorException the wx error exception
+   * @param collection       集合名称
+   * @param whereJson        查询条件JSON字符串
+   * @param updateJson       更新内容JSON字符串
+   * @return                 更新结果对象
+   * @throws WxErrorException 更新失败时抛出
    */
   WxCloudDatabaseUpdateResult update(String collection, String whereJson, String updateJson) throws WxErrorException;
 
   /**
-   * Database update wx cloud database update result.
+   * 数据库更新记录。
    *
-   * @param query the query
-   * @return the wx cloud database update result
-   * @throws WxErrorException the wx error exception
+   * @param query            数据库操作语句
+   * @return                 更新结果对象
+   * @throws WxErrorException 更新失败时抛出
    */
   WxCloudDatabaseUpdateResult databaseUpdate(String query) throws WxErrorException;
 
   /**
-   * <pre>
-   * 数据库更新记录
-   *
+   * 数据库更新记录。
    * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseUpdate.html
-   * 请求地址：POST https://api.weixin.qq.com/tcb/databaseupdate?access_token=ACCESS_TOKEN
-   * </pre>
    *
-   * @param env   云环境ID
-   * @param query 数据库操作语句
-   * @return . wx cloud database update result
-   * @throws WxErrorException .
+   * @param env              云环境ID
+   * @param query            数据库操作语句
+   * @return                 更新结果对象
+   * @throws WxErrorException 更新失败时抛出
    */
   WxCloudDatabaseUpdateResult databaseUpdate(String env, String query) throws WxErrorException;
 
   /**
+   * 查询集合中的记录。
+   * 示例：
    * db.collection('geo')
-   * .where({
-   * price: _.gt(10)
-   * })
-   * .orderBy('_id', 'asc')
-   * .orderBy('price', 'desc')
-   * .skip(1)
-   * .limit(10)
-   * .get()
-   *
-   * @param collection the collection
-   * @param whereJson  the where json
-   * @param orderBy    the order by
-   * @param skip       the skip
-   * @param limit      the limit
-   * @return wx cloud database query result
-   * @throws WxErrorException the wx error exception
+   *   .where({price: _.gt(10)})
+   *   .orderBy('_id', 'asc')
+   *   .orderBy('price', 'desc')
+   *   .skip(1)
+   *   .limit(10)
+   *   .get()
+   *
+   * @param collection       集合名称
+   * @param whereJson        查询条件JSON字符串
+   * @param orderBy          排序条件Map
+   * @param skip             跳过记录数
+   * @param limit            限制返回记录数
+   * @return                 查询结果对象
+   * @throws WxErrorException 查询失败时抛出
    */
   WxCloudDatabaseQueryResult query(String collection, String whereJson, Map<String, String> orderBy,
                                    Integer skip, Integer limit) throws WxErrorException;
 
   /**
-   * Database query wx cloud database query result.
+   * 数据库查询记录。
    *
-   * @param query the query
-   * @return the wx cloud database query result
-   * @throws WxErrorException the wx error exception
+   * @param query            数据库操作语句
+   * @return                 查询结果对象
+   * @throws WxErrorException 查询失败时抛出
    */
   WxCloudDatabaseQueryResult databaseQuery(String query) throws WxErrorException;
 
   /**
-   * <pre>
-   * 数据库查询记录
-   *
+   * 数据库查询记录。
    * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseQuery.html
-   * 请求地址：POST https://api.weixin.qq.com/tcb/databasequery?access_token=ACCESS_TOKEN
-   * </pre>
    *
-   * @param env   云环境ID
-   * @param query 数据库操作语句
-   * @return . wx cloud database query result
-   * @throws WxErrorException .
+   * @param env              云环境ID
+   * @param query            数据库操作语句
+   * @return                 查询结果对象
+   * @throws WxErrorException 查询失败时抛出
    */
   WxCloudDatabaseQueryResult databaseQuery(String env, String query) throws WxErrorException;
 
   /**
-   * Database aggregate json array.
+   * 数据库聚合记录。
    *
-   * @param query the query
-   * @return the json array
-   * @throws WxErrorException the wx error exception
+   * @param query            数据库操作语句
+   * @return                 聚合结果JSON数组
+   * @throws WxErrorException 聚合失败时抛出
    */
   JsonArray databaseAggregate(String query) throws WxErrorException;
 
   /**
-   * <pre>
-   * 数据库聚合记录
-   *
+   * 数据库聚合记录。
    * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseAggregate.html
-   * 请求地址：POST https://api.weixin.qq.com/tcb/databaseaggregate?access_token=ACCESS_TOKEN
-   * </pre>
    *
-   * @param env   云环境ID
-   * @param query 数据库操作语句
-   * @return . json array
-   * @throws WxErrorException .
+   * @param env              云环境ID
+   * @param query            数据库操作语句
+   * @return                 聚合结果JSON数组
+   * @throws WxErrorException 聚合失败时抛出
    */
   JsonArray databaseAggregate(String env, String query) throws WxErrorException;
 
   /**
-   * Count long.
+   * 统计集合中符合条件的记录数。
    *
-   * @param collection the collection
-   * @param whereJson  the where json
-   * @return the long
-   * @throws WxErrorException the wx error exception
+   * @param collection       集合名称
+   * @param whereJson        查询条件JSON字符串
+   * @return                 记录数量
+   * @throws WxErrorException 统计失败时抛出
    */
   Long count(String collection, String whereJson) throws WxErrorException;
 
   /**
-   * Database count long.
+   * 统计集合记录数或统计查询语句对应的结果记录数。
    *
-   * @param query the query
-   * @return the long
-   * @throws WxErrorException the wx error exception
+   * @param query            数据库操作语句
+   * @return                 记录数量
+   * @throws WxErrorException 统计失败时抛出
    */
   Long databaseCount(String query) throws WxErrorException;
 
   /**
-   * <pre>
-   * 统计集合记录数或统计查询语句对应的结果记录数
-   *
+   * 统计集合记录数或统计查询语句对应的结果记录数。
    * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseCount.html
-   * 请求地址：POST https://api.weixin.qq.com/tcb/databasecount?access_token=ACCESS_TOKEN
-   * </pre>
    *
-   * @param env   云环境ID
-   * @param query 数据库操作语句
-   * @return 记录数量 long
-   * @throws WxErrorException .
+   * @param env              云环境ID
+   * @param query            数据库操作语句
+   * @return                 记录数量
+   * @throws WxErrorException 统计失败时抛出
    */
   Long databaseCount(String env, String query) throws WxErrorException;
 
   /**
-   * Update index.
+   * 变更数据库索引。
    *
-   * @param collectionName the collection name
-   * @param createIndexes  the create indexes
-   * @param dropIndexNames the drop index names
-   * @throws WxErrorException the wx error exception
+   * @param collectionName   集合名称
+   * @param createIndexes    新增索引对象列表
+   * @param dropIndexNames   要删除的索引名称列表
+   * @throws WxErrorException 更新失败时抛出
    */
   void updateIndex(String collectionName, List<WxCloudDatabaseCreateIndexRequest> createIndexes,
                    List<String> dropIndexNames) throws WxErrorException;
 
   /**
-   * <pre>
-   * 变更数据库索引
-   *
+   * 变更数据库索引。
    * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/updateIndex.html
-   * 请求地址：POST https://api.weixin.qq.com/tcb/updateindex?access_token=ACCESS_TOKEN
-   * </pre>
    *
-   * @param env            云环境ID
-   * @param collectionName 集合名称
-   * @param createIndexes  新增索引对象
-   * @param dropIndexNames 要删除的索引的名字
-   * @throws WxErrorException .
+   * @param env              云环境ID
+   * @param collectionName   集合名称
+   * @param createIndexes    新增索引对象列表
+   * @param dropIndexNames   要删除的索引名称列表
+   * @throws WxErrorException 更新失败时抛出
    */
   void updateIndex(String env, String collectionName, List<WxCloudDatabaseCreateIndexRequest> createIndexes,
                    List<String> dropIndexNames) throws WxErrorException;
 
   /**
-   * Database migrate import long.
+   * 数据库导入。
    *
-   * @param collectionName the collection name
-   * @param filePath       the file path
-   * @param fileType       the file type
-   * @param stopOnError    the stop on error
-   * @param conflictMode   the conflict mode
-   * @return the long
-   * @throws WxErrorException the wx error exception
+   * @param collectionName   导入collection名
+   * @param filePath         导入文件路径
+   * @param fileType         导入文件类型，1：JSON，2：CSV
+   * @param stopOnError      是否在遇到错误时停止导入
+   * @param conflictMode     冲突处理模式，1：INSERT，2：UPSERT
+   * @return                 任务ID
+   * @throws WxErrorException 导入失败时抛出
    */
   Long databaseMigrateImport(String collectionName, String filePath, int fileType,
                              boolean stopOnError, int conflictMode) throws WxErrorException;
 
   /**
-   * <pre>
-   * 数据库导入
+   * 数据库导入。
+   * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseMigrateImport.html
+   * 注意：导入文件需先上传到同环境的存储中，可使用开发者工具或HTTP API的上传文件API上传
    *
-   * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseMigrateImport
-   * .html
-   * 请求地址： POST https://api.weixin.qq.com/tcb/databasemigrateimport?access_token=ACCESS_TOKEN
-   * </pre>
-   *
-   * @param env            云环境ID
-   * @param collectionName 导入collection名
-   * @param filePath       导入文件路径(导入文件需先上传到同环境的存储中，可使用开发者工具或 HTTP API的上传文件 API上传）
-   * @param fileType       导入文件类型， 1	JSON， 2	CSV
-   * @param stopOnError    是否在遇到错误时停止导入
-   * @param conflictMode   冲突处理模式 ： 1	INSERT	,    2	UPSERT
-   * @return jobId long
-   * @throws WxErrorException .
+   * @param env              云环境ID
+   * @param collectionName   导入collection名
+   * @param filePath         导入文件路径
+   * @param fileType         导入文件类型，1：JSON，2：CSV
+   * @param stopOnError      是否在遇到错误时停止导入
+   * @param conflictMode     冲突处理模式，1：INSERT，2：UPSERT
+   * @return                 任务ID
+   * @throws WxErrorException 导入失败时抛出
    */
   Long databaseMigrateImport(String env, String collectionName, String filePath, int fileType, boolean stopOnError,
                              int conflictMode) throws WxErrorException;
 
   /**
-   * Database migrate export long.
+   * 数据库导出。
    *
-   * @param filePath the file path
-   * @param fileType the file type
-   * @param query    the query
-   * @return the long
-   * @throws WxErrorException the wx error exception
+   * @param filePath         导出文件路径
+   * @param fileType         导出文件类型，1：JSON，2：CSV
+   * @param query            导出条件
+   * @return                 任务ID
+   * @throws WxErrorException 导出失败时抛出
    */
   Long databaseMigrateExport(String filePath, int fileType, String query) throws WxErrorException;
 
   /**
-   * <pre>
-   * 数据库导出
-   *
-   * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseMigrateExport
-   * .html
-   * 请求地址： POST https://api.weixin.qq.com/tcb/databasemigrateexport?access_token=ACCESS_TOKEN
-   * </pre>
+   * 数据库导出。
+   * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseMigrateExport.html
+   * 注意：文件会导出到同环境的云存储中，可使用获取下载链接API获取下载链接
    *
-   * @param env      云环境ID
-   * @param filePath 导出文件路径（文件会导出到同环境的云存储中，可使用获取下载链接 API 获取下载链接）
-   * @param fileType 导出文件类型， 1	JSON， 2	CSV
-   * @param query    导出条件
-   * @return jobId long
-   * @throws WxErrorException .
+   * @param env              云环境ID
+   * @param filePath         导出文件路径
+   * @param fileType         导出文件类型，1：JSON，2：CSV
+   * @param query            导出条件
+   * @return                 任务ID
+   * @throws WxErrorException 导出失败时抛出
    */
   Long databaseMigrateExport(String env, String filePath, int fileType, String query) throws WxErrorException;
 
   /**
-   * Database migrate query info wx cloud cloud database migrate query info result.
+   * 数据库迁移状态查询。
    *
-   * @param jobId the job id
-   * @return the wx cloud cloud database migrate query info result
-   * @throws WxErrorException the wx error exception
+   * @param jobId            迁移任务ID
+   * @return                 迁移状态查询结果
+   * @throws WxErrorException 查询失败时抛出
    */
   WxCloudCloudDatabaseMigrateQueryInfoResult databaseMigrateQueryInfo(Long jobId) throws WxErrorException;
 
   /**
-   * <pre>
-   *   数据库迁移状态查询
-   *
-   *  文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database
-   *  /databaseMigrateQueryInfo.html
-   *  请求地址：POST https://api.weixin.qq.com/tcb/databasemigratequeryinfo?access_token=ACCESS_TOKEN
-   * </pre>
+   * 数据库迁移状态查询。
+   * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseMigrateQueryInfo.html
    *
-   * @param env   云环境ID
-   * @param jobId 迁移任务ID
-   * @return . wx cloud cloud database migrate query info result
-   * @throws WxErrorException .
+   * @param env              云环境ID
+   * @param jobId            迁移任务ID
+   * @return                 迁移状态查询结果
+   * @throws WxErrorException 查询失败时抛出
    */
   WxCloudCloudDatabaseMigrateQueryInfoResult databaseMigrateQueryInfo(String env, Long jobId) throws WxErrorException;
 
   /**
-   * Upload file wx cloud upload file result.
+   * 获取文件上传链接。
    *
-   * @param path the path
-   * @return the wx cloud upload file result
-   * @throws WxErrorException the wx error exception
+   * @param path             上传路径
+   * @return                 上传结果对象
+   * @throws WxErrorException 获取失败时抛出
    */
   WxCloudUploadFileResult uploadFile(String path) throws WxErrorException;
 
   /**
-   * <pre>
-   * 获取文件上传链接
-   *
+   * 获取文件上传链接。
    * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/storage/uploadFile.html
-   * 请求地址：POST https://api.weixin.qq.com/tcb/uploadfile?access_token=ACCESS_TOKEN
-   *
-   * </pre>
    *
-   * @param env  云环境ID
-   * @param path 上传路径
-   * @return 上传结果 wx cloud upload file result
-   * @throws WxErrorException .
+   * @param env              云环境ID
+   * @param path             上传路径
+   * @return                 上传结果对象
+   * @throws WxErrorException 获取失败时抛出
    */
   WxCloudUploadFileResult uploadFile(String env, String path) throws WxErrorException;
 
   /**
-   * Batch download file wx cloud batch download file result.
+   * 获取文件下载链接。
    *
-   * @param fileIds the file ids
-   * @param maxAges the max ages
-   * @return the wx cloud batch download file result
-   * @throws WxErrorException the wx error exception
+   * @param fileIds          文件ID数组
+   * @param maxAges          下载链接有效期数组，对应文件id列表
+   * @return                 下载链接信息对象
+   * @throws WxErrorException 获取失败时抛出
    */
   WxCloudBatchDownloadFileResult batchDownloadFile(String[] fileIds, long[] maxAges) throws WxErrorException;
 
   /**
-   * <pre>
-   * 获取文件下载链接
-   *
+   * 获取文件下载链接。
    * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/storage/batchDownloadFile.html
-   * 请求地址：POST https://api.weixin.qq.com/tcb/batchdownloadfile?access_token=ACCESS_TOKEN
-   *
-   * </pre>
    *
-   * @param env     云环境ID
-   * @param fileIds 文件ID列表
-   * @param maxAges 下载链接有效期列表，对应文件id列表
-   * @return 下载链接信息 wx cloud batch download file result
-   * @throws WxErrorException .
+   * @param env              云环境ID
+   * @param fileIds          文件ID数组
+   * @param maxAges          下载链接有效期数组，对应文件id列表
+   * @return                 下载链接信息对象
+   * @throws WxErrorException 获取失败时抛出
    */
   WxCloudBatchDownloadFileResult batchDownloadFile(String env, String[] fileIds, long[] maxAges) throws WxErrorException;
 
   /**
-   * Batch delete file wx cloud batch delete file result.
+   * 删除文件。
    *
-   * @param fileIds the file ids
-   * @return the wx cloud batch delete file result
-   * @throws WxErrorException the wx error exception
+   * @param fileIds          文件ID数组
+   * @return                 删除结果对象
+   * @throws WxErrorException 删除失败时抛出
    */
   WxCloudBatchDeleteFileResult batchDeleteFile(String[] fileIds) throws WxErrorException;
 
   /**
-   * <pre>
-   * 删除文件
-   *
+   * 删除文件。
    * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/storage/batchDeleteFile.html
-   * 请求地址：POST https://api.weixin.qq.com/tcb/batchdeletefile?access_token=ACCESS_TOKEN
-   *
-   * </pre>
    *
-   * @param env     云环境ID
-   * @param fileIds 文件ID列表
-   * @return 下载链接信息 wx cloud batch delete file result
-   * @throws WxErrorException .
+   * @param env              云环境ID
+   * @param fileIds          文件ID数组
+   * @return                 删除结果对象
+   * @throws WxErrorException 删除失败时抛出
    */
   WxCloudBatchDeleteFileResult batchDeleteFile(String env, String[] fileIds) throws WxErrorException;
 
   /**
-   * <pre>
-   *  获取腾讯云API调用凭证
-   *
-   *  文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/utils/getQcloudToken.html
-   *  请求地址：POST https://api.weixin.qq.com/tcb/getqcloudtoken?access_token=ACCESS_TOKEN
-   * </pre>
+   * 获取腾讯云API调用凭证。
+   * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/utils/getQcloudToken.html
    *
-   * @param lifeSpan 有效期（单位为秒，最大7200）
-   * @return . qcloud token
-   * @throws WxErrorException .
+   * @param lifeSpan         有效期（单位为秒，最大7200）
+   * @return                 腾讯云Token结果对象
+   * @throws WxErrorException 获取失败时抛出
    */
   WxCloudGetQcloudTokenResult getQcloudToken(long lifeSpan) throws WxErrorException;
 
   /**
-   * Database collection add.
+   * 新增集合。
    *
-   * @param collectionName the collection name
-   * @throws WxErrorException the wx error exception
+   * @param collectionName   集合名称
+   * @throws WxErrorException 新增失败时抛出
    */
   void databaseCollectionAdd(String collectionName) throws WxErrorException;
 
   /**
-   * <pre>
-   * 新增集合
+   * 新增集合。
+   * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseCollectionAdd.html
    *
-   * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseCollectionAdd
-   * .html
-   * 请求地址：POST https://api.weixin.qq.com/tcb/databasecollectionadd?access_token=ACCESS_TOKEN
-   * </pre>
-   *
-   * @param env            云环境ID
-   * @param collectionName 集合名称
-   * @throws WxErrorException .
+   * @param env              云环境ID
+   * @param collectionName   集合名称
+   * @throws WxErrorException 新增失败时抛出
    */
   void databaseCollectionAdd(String env, String collectionName) throws WxErrorException;
 
   /**
-   * Database collection delete.
+   * 删除集合。
    *
-   * @param collectionName the collection name
-   * @throws WxErrorException the wx error exception
+   * @param collectionName   集合名称
+   * @throws WxErrorException 删除失败时抛出
    */
   void databaseCollectionDelete(String collectionName) throws WxErrorException;
 
   /**
-   * <pre>
-   * 删除集合
-   *
-   * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database
-   * /databaseCollectionDelete.html
-   * 请求地址：POST https://api.weixin.qq.com/tcb/databasecollectionadd?access_token=ACCESS_TOKEN
-   * </pre>
+   * 删除集合。
+   * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseCollectionDelete.html
    *
-   * @param env            云环境ID
-   * @param collectionName 集合名称
-   * @throws WxErrorException .
+   * @param env              云环境ID
+   * @param collectionName   集合名称
+   * @throws WxErrorException 删除失败时抛出
    */
   void databaseCollectionDelete(String env, String collectionName) throws WxErrorException;
 
   /**
-   * Database collection get wx cloud database collection get result.
+   * 获取特定云环境下集合信息。
    *
-   * @param limit  the limit
-   * @param offset the offset
-   * @return the wx cloud database collection get result
-   * @throws WxErrorException the wx error exception
+   * @param limit            获取数量限制，默认值：10
+   * @param offset           偏移量，默认值：0
+   * @return                 集合信息获取结果对象
+   * @throws WxErrorException 获取失败时抛出
    */
   WxCloudDatabaseCollectionGetResult databaseCollectionGet(Long limit, Long offset) throws WxErrorException;
 
   /**
-   * <pre>
-   * 获取特定云环境下集合信息
-   *
-   * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseCollectionGet
-   * .html
-   * 请求地址：POST https://api.weixin.qq.com/tcb/databasecollectionget?access_token=ACCESS_TOKEN
-   * </pre>
+   * 获取特定云环境下集合信息。
+   * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/database/databaseCollectionGet.html
    *
-   * @param env    云环境ID
-   * @param limit  获取数量限制，默认值：10
-   * @param offset 偏移量,默认值：0
-   * @return . wx cloud database collection get result
-   * @throws WxErrorException .
+   * @param env              云环境ID
+   * @param limit            获取数量限制，默认值：10
+   * @param offset           偏移量，默认值：0
+   * @return                 集合信息获取结果对象
+   * @throws WxErrorException 获取失败时抛出
    */
   WxCloudDatabaseCollectionGetResult databaseCollectionGet(String env, Long limit, Long offset) throws WxErrorException;
 
   /**
-   * 发送携带 URL Link 的短信
-   *
+   * 发送携带 URL Link 的短信。
    * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/cloudbase/cloudbase.sendSmsV2.html
-   * @param request
-   * @return WxCloudSendSmsV2Result
-   * @throws WxErrorException
+   *
+   * @param request          短信发送请求对象
+   * @return                 短信发送结果对象
+   * @throws WxErrorException 发送失败时抛出
    */
   WxCloudSendSmsV2Result sendSmsV2(WxCloudSendSmsV2Request request) throws WxErrorException;
-
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaExpressDeliveryReturnService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaExpressDeliveryReturnService.java
index 4254d18dfe..6d950f6801 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaExpressDeliveryReturnService.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaExpressDeliveryReturnService.java
@@ -5,18 +5,47 @@
 import me.chanjar.weixin.common.error.WxErrorException;
 
 /**
- * 退货组件
+ * 微信小程序物流退货组件接口。
+ * 用于处理退货单相关操作，包括新增、查询和取消退货单。
+ * 文档：https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/express/express.html
+ *
  */
 public interface WxMaExpressDeliveryReturnService {
 
-    /**
-     * 获取支持的快递公司列表
-     */
+    /** 新增退货单接口地址 */
     String ADD_DELIVERY_RETURN_URL = "https://api.weixin.qq.com/cgi-bin/express/delivery/return/add";
+    /** 获取退货单接口地址 */
     String GET_DELIVERY_RETURN_URL = "https://api.weixin.qq.com/cgi-bin/express/delivery/return/get";
+    /** 取消退货单接口地址 */
     String UNBIND_DELIVERY_RETURN_URL = "https://api.weixin.qq.com/cgi-bin/express/delivery/return/unbind";
 
+    /**
+     * 新增退货单。
+     * 用于创建新的退货单，返回退货单信息。
+     *
+     * @param wxMaExpressDeliveryReturnAddRequest 退货单新增请求对象
+     * @return                                    退货单信息结果
+     * @throws WxErrorException                   新增失败时抛出
+     */
     WxMaExpressReturnInfoResult addDeliveryReturn(WxMaExpressDeliveryReturnAddRequest wxMaExpressDeliveryReturnAddRequest) throws WxErrorException;
+
+    /**
+     * 获取退货单信息。
+     * 根据退货单ID查询退货单的详细信息。
+     *
+     * @param returnId          退货单ID
+     * @return                  退货单信息结果
+     * @throws WxErrorException 获取失败时抛出
+     */
     WxMaExpressReturnInfoResult getDeliveryReturn(String returnId) throws WxErrorException;
+
+    /**
+     * 取消退货单。
+     * 取消指定的退货单，取消后的退货单将无法继续使用。
+     *
+     * @param returnId          退货单ID
+     * @return                  操作结果
+     * @throws WxErrorException 取消失败时抛出
+     */
     WxMaExpressReturnInfoResult unbindDeliveryReturn(String returnId) throws WxErrorException;
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaIntracityService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaIntracityService.java
index 80cd88b463..4359fc7b1c 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaIntracityService.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaIntracityService.java
@@ -57,7 +57,7 @@ WxMaStoreBalance balanceQuery(String wxStoreId, String serviceTransId, PayMode p
   WxMaGetPayModeResponse getPayMode() throws WxErrorException;
 
   /** 查询运费 */
-  WxMaAddOrderResponse preAddOrder(WxMaPreAddOrderRequest request) throws WxErrorException;
+  WxMaPreAddOrderResponse preAddOrder(WxMaPreAddOrderRequest request) throws WxErrorException;
 
   /** 创建配送单 */
   WxMaAddOrderResponse addOrder(WxMaAddOrderRequest order) throws WxErrorException;
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaOrderManagementService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaOrderManagementService.java
new file mode 100644
index 0000000000..91980e9427
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaOrderManagementService.java
@@ -0,0 +1,39 @@
+package cn.binarywang.wx.miniapp.api;
+
+import cn.binarywang.wx.miniapp.bean.order.WxMaOrderManagementGetOrderDetailPath;
+import cn.binarywang.wx.miniapp.bean.order.WxMaOrderManagementResult;
+import me.chanjar.weixin.common.error.WxErrorException;
+
+/**
+ * @author xzh
+ * @Description
+ * @createTime 2025/01/16 15:20
+ */
+public interface WxMaOrderManagementService {
+
+  /**
+   * 查询订单详情路径
+   * 注意事项
+   * 如果没有配置过订单详情路径，会返回成功，其中path为''。
+   *
+   * @return WxMaOrderManagementGetOrderDetailPath
+   * @throws WxErrorException e
+   */
+  WxMaOrderManagementGetOrderDetailPath getOrderDetailPath()
+    throws WxErrorException;
+
+
+  /**
+   * 配置订单详情路径
+   * 注意事项
+   * 调用接口前需要先完成订单中心授权协议签署。
+   * 请确保配置的path可正常跳转到小程序，并且path必须包含字符串“${商品订单号}”。
+   *
+   * @param path 订单详情路径
+   * @return WxMaOrderManagementResult
+   * @throws WxErrorException e
+   */
+  WxMaOrderManagementResult updateOrderDetailPath(String path)
+    throws WxErrorException;
+
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaOrderShippingService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaOrderShippingService.java
index 322d740d5b..8332ae7af4 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaOrderShippingService.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaOrderShippingService.java
@@ -1,10 +1,7 @@
 package cn.binarywang.wx.miniapp.api;
 
 import cn.binarywang.wx.miniapp.bean.shop.request.shipping.*;
-import cn.binarywang.wx.miniapp.bean.shop.response.WxMaOrderShippingInfoBaseResponse;
-import cn.binarywang.wx.miniapp.bean.shop.response.WxMaOrderShippingInfoGetListResponse;
-import cn.binarywang.wx.miniapp.bean.shop.response.WxMaOrderShippingInfoGetResponse;
-import cn.binarywang.wx.miniapp.bean.shop.response.WxMaOrderShippingIsTradeManagedResponse;
+import cn.binarywang.wx.miniapp.bean.shop.response.*;
 import me.chanjar.weixin.common.error.WxErrorException;
 
 /**
@@ -86,4 +83,25 @@ WxMaOrderShippingInfoBaseResponse notifyConfirmReceive(WxMaOrderShippingInfoNoti
    */
   WxMaOrderShippingInfoBaseResponse setMsgJumpPath(String path)
     throws WxErrorException;
+
+  /**
+   * 查询小程序是否已完成交易结算管理确认
+   *
+   * @param appId 待查询小程序的 appid，非服务商调用时仅能查询本账号
+   * @return WxMaOrderShippingITMCCompletedResult
+   * @throws WxErrorException e
+   */
+  WxMaOrderShippingITMCCompletedResult isTradeManagementConfirmationCompleted(String appId)
+    throws WxErrorException;
+
+  /**
+   * 特殊发货报备
+   * @param orderId  需要特殊发货报备的订单号，可传入微信支付单号或商户单号
+   * @param type 特殊发货报备类型，1为预售商品订单，2为测试订单
+   * @param delayTo 预计发货时间的unix时间戳，type为1时必填，type为2可省略
+   * @return WxMaOrderShippingInfoBaseResponse
+   * @throws WxErrorException e
+   */
+  WxMaOrderShippingInfoBaseResponse opSpecialOrder(String orderId, Integer type, Long delayTo)
+    throws WxErrorException;
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaProductService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaProductService.java
index b629772a27..1c4bbb56c9 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaProductService.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaProductService.java
@@ -5,18 +5,16 @@
 import cn.binarywang.wx.miniapp.bean.product.WxMinishopGetBrandResponse;
 import cn.binarywang.wx.miniapp.bean.product.WxMinishopGetCategoryResponse;
 import cn.binarywang.wx.miniapp.bean.product.WxMinishopGetFrightTemplateResponse;
-import cn.binarywang.wx.miniapp.bean.product.WxMinishopOrderListResponse;
 import cn.binarywang.wx.miniapp.bean.product.WxMinishopResult;
 import cn.binarywang.wx.miniapp.bean.product.WxMinishopSku;
 import cn.binarywang.wx.miniapp.bean.product.WxMinishopSkuListResponse;
 import cn.binarywang.wx.miniapp.bean.product.WxMinishopSpu;
-import cn.binarywang.wx.miniapp.bean.product.WxMinishopSpuGet;
 import cn.binarywang.wx.miniapp.bean.product.WxMinishopSpuGetResponse;
 import cn.binarywang.wx.miniapp.bean.product.WxMinishopSpuListResponse;
 import cn.binarywang.wx.miniapp.bean.product.WxMinishopUpdateGoodsSkuData;
 import cn.binarywang.wx.miniapp.bean.shop.request.WxMaShopSpuPageRequest;
 import cn.binarywang.wx.miniapp.bean.shop.response.WxMaShopBaseResponse;
-import cn.binarywang.wx.miniapp.bean.shop.response.WxMaShopGetSpuListResponse;
+
 import java.io.File;
 import java.util.List;
 import me.chanjar.weixin.common.bean.result.WxMinishopImageUploadResult;
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java
index 9d55df3797..87405edd8b 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaService.java
@@ -16,7 +16,7 @@
 import me.chanjar.weixin.common.util.http.RequestHttp;
 
 /**
- * The interface Wx ma service.
+ * 微信小程序主服务接口，定义了所有小程序相关的核心操作方法。
  *
  * @author <a href="https://github.com/binarywang">Binary Wang</a>
  */
@@ -37,557 +37,565 @@ public interface WxMaService extends WxService {
   String SET_DYNAMIC_DATA_URL = "https://api.weixin.qq.com/wxa/setdynamicdata";
 
   /**
-   * 获取登录后的session信息.
+   * 获取登录后的 session 信息。
    *
-   * @param jsCode 登录时获取的 code
-   * @return the wx ma jscode 2 session result
-   * @throws WxErrorException the wx error exception
+   * @param jsCode           登录时获取的 code
+   * @return                 登录 session 结果对象
+   * @throws WxErrorException 调用微信接口失败时抛出
    */
   WxMaJscode2SessionResult jsCode2SessionInfo(String jsCode) throws WxErrorException;
 
   /**
-   * 导入抽样数据
-   *
-   * <pre>
+   * 导入抽样数据到微信后台，用于流量分配。
    * 第三方通过调用微信API，将数据写入到setdynamicdata这个API。每个Post数据包不超过5K，若数据过多可开多进（线）程并发导入数据（例如：数据量为十万量级可以开50个线程并行导数据）。
    * 文档地址：https://wsad.weixin.qq.com/wsad/zh_CN/htmledition/widget-docs-v3/html/custom/quickstart/implement/import/index.html
    * http请求方式：POST http(s)://api.weixin.qq.com/wxa/setdynamicdata?access_token=ACCESS_TOKEN
-   * </pre>
    *
-   * @param lifespan 数据有效时间，秒为单位，一般为86400，一天一次导入的频率
-   * @param type 用于标识数据所属的服务类目
-   * @param scene 1代表用于搜索的数据
-   * @param data 推送到微信后台的数据列表，该数据被微信用于流量分配，注意该字段为string类型而不是object
-   * @throws WxErrorException .
+   * @param lifespan         数据有效时间（秒），如 86400 表示一天
+   * @param type             数据所属服务类目标识
+   * @param scene            场景值，1 代表用于搜索的数据
+   * @param data             推送到微信后台的数据列表（字符串类型）
+   * @throws WxErrorException 调用微信接口失败时抛出
    */
   void setDynamicData(int lifespan, String type, int scene, String data) throws WxErrorException;
 
   /**
-   *
-   *
-   * <pre>
-   * 验证消息的确来自微信服务器.
+   * 校验消息是否来自微信服务器。
    * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319&token=&lang=zh_CN
-   * </pre>
    *
-   * @param timestamp the timestamp
-   * @param nonce the nonce
-   * @param signature the signature
-   * @return the boolean
+   * @param timestamp        时间戳
+   * @param nonce            随机数
+   * @param signature        签名字符串
+   * @return                 校验通过返回 true，否则返回 false
    */
   boolean checkSignature(String timestamp, String nonce, String signature);
 
   /**
-   * 获取access_token, 不强制刷新access_token.
+   * 获取 access_token，不强制刷新。
    *
-   * @return the access token
-   * @throws WxErrorException the wx error exception
-   * @see #getAccessToken(boolean) #getAccessToken(boolean)
+   * @return                 access_token 字符串
+   * @throws WxErrorException 调用微信接口失败时抛出
+   * @see #getAccessToken(boolean)
    */
   String getAccessToken() throws WxErrorException;
 
   /**
+   * 获取 access_token，本方法线程安全。多线程同时刷新时只刷新一次，避免超出调用次数上限。
+   * 一般无需主动调用，所有接口会自动处理 token 过期。
+   * 详情见：http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183&token=&lang=zh_CN
    *
-   *
-   * <pre>
-   * 获取access_token，本方法线程安全.
-   * 且在多线程同时刷新时只刷新一次，避免超出2000次/日的调用次数上限
-   *
-   * 另：本service的所有方法都会在access_token过期是调用此方法
-   *
-   * 程序员在非必要情况下尽量不要主动调用此方法
-   *
-   * 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183&token=&lang=zh_CN
-   * </pre>
-   *
-   * @param forceRefresh 强制刷新
-   * @return the access token
-   * @throws WxErrorException the wx error exception
+   * @param forceRefresh     是否强制刷新
+   * @return                 access_token 字符串
+   * @throws WxErrorException 调用微信接口失败时抛出
    */
   String getAccessToken(boolean forceRefresh) throws WxErrorException;
 
   /**
-   *
-   *
-   * <pre>
    * 用户支付完成后，获取该用户的 UnionId，无需用户授权。本接口支持第三方平台代理查询。
-   *
    * 注意：调用前需要用户完成支付，且在支付后的五分钟内有效。
    * 请求地址： GET https://api.weixin.qq.com/wxa/getpaidunionid?access_token=ACCESS_TOKEN&openid=OPENID
-   * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/api/getPaidUnionId.html
-   * </pre>
+   * 文档：https://developers.weixin.qq.com/miniprogram/dev/api/getPaidUnionId.html
    *
-   * @param openid 必填 支付用户唯一标识
-   * @param transactionId 非必填 微信支付订单号
-   * @param mchId 非必填 微信支付分配的商户号，和商户订单号配合使用
-   * @param outTradeNo 非必填 微信支付商户订单号，和商户号配合使用
-   * @return UnionId. paid union id
-   * @throws WxErrorException .
+   * @param openid           支付用户唯一标识（必填）
+   * @param transactionId    微信支付订单号（可选）
+   * @param mchId            微信支付分配的商户号，与商户订单号配合使用（可选）
+   * @param outTradeNo       微信支付商户订单号，与商户号配合使用（可选）
+   * @return                 用户的 UnionId
+   * @throws WxErrorException 调用微信接口失败时抛出
    */
   String getPaidUnionId(String openid, String transactionId, String mchId, String outTradeNo)
       throws WxErrorException;
 
   /**
+   * 执行自定义的微信API请求。
+   * <br>
+   * Service没有实现某个API的时候，可以用这个方法，比{@link #get}和{@link #post}方法更灵活，可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。
+   * 可以参考 {@link MediaUploadRequestExecutor} 的实现方法。
    *
-   *
-   * <pre>
-   * Service没有实现某个API的时候，可以用这个，
-   * 比{@link #get}和{@link #post}方法更灵活，可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。
-   * 可以参考，{@link MediaUploadRequestExecutor}的实现方法
-   * </pre>
-   *
-   * @param <T> .
-   * @param <E> .
-   * @param executor 执行器
-   * @param uri 接口请求地址
-   * @param data 参数或请求数据
-   * @return . t
-   * @throws WxErrorException the wx error exception
+   * @param <T>              返回的数据类型
+   * @param <E>              请求参数的数据类型
+   * @param executor         执行器对象
+   * @param uri              接口请求地址
+   * @param data             请求参数或数据
+   * @return                 微信接口返回的数据对象
+   * @throws WxErrorException 微信接口调用异常
    */
   <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException;
 
+  /**
+   * 执行带有签名的微信API请求。
+   *
+   * @param executor         签名请求执行器
+   * @param uri              接口请求地址
+   * @param headers          请求头信息
+   * @param data             请求数据
+   * @return                 微信接口响应对象
+   * @throws WxErrorException 微信接口调用异常
+   */
   WxMaApiResponse execute(
-      ApiSignaturePostRequestExecutor executor,
+      ApiSignaturePostRequestExecutor<?, ?> executor,
       String uri,
       Map<String, String> headers,
       String data)
       throws WxErrorException;
 
   /**
+   * 设置微信系统繁忙时的重试等待时间（毫秒）。
    *
-   *
-   * <pre>
-   * 设置当微信系统响应系统繁忙时，要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试.
-   * 默认：1000ms
-   * </pre>
-   *
-   * @param retrySleepMillis 重试等待毫秒数
+   * @param retrySleepMillis 重试等待的毫秒数，默认1000ms
    */
   void setRetrySleepMillis(int retrySleepMillis);
 
   /**
+   * 设置微信系统繁忙时的最大重试次数。
    *
-   *
-   * <pre>
-   * 设置当微信系统响应系统繁忙时，最大重试次数.
-   * 默认：5次
-   * </pre>
-   *
-   * @param maxRetryTimes 最大重试次数
+   * @param maxRetryTimes    最大重试次数，默认5次
    */
   void setMaxRetryTimes(int maxRetryTimes);
 
   /**
-   * 获取WxMaConfig 对象.
+   * 获取当前小程序的配置信息对象。
    *
-   * @return WxMaConfig wx ma config
+   * @return                 当前小程序的WxMaConfig配置对象
    */
   WxMaConfig getWxMaConfig();
 
   /**
-   * 注入 {@link WxMaConfig} 的实现.
+   * 注入小程序配置信息。
    *
-   * @param maConfig config
+   * @param maConfig         小程序配置信息对象
    */
   void setWxMaConfig(WxMaConfig maConfig);
 
   /**
-   * Map里 加入新的 {@link WxMaConfig}，适用于动态添加新的微信公众号配置.
+   * 动态添加新的小程序配置信息。
    *
-   * @param miniappId 小程序标识
-   * @param configStorage 新的微信配置
+   * @param miniappId        小程序唯一标识
+   * @param configStorage    新的小程序配置信息
    */
   void addConfig(String miniappId, WxMaConfig configStorage);
 
   /**
-   * 从 Map中 移除 {@link String miniappId} 所对应的 {@link WxMaConfig}，适用于动态移除小程序配置.
+   * 动态移除指定小程序的配置信息。
    *
-   * @param miniappId 对应小程序的标识
+   * @param miniappId        小程序唯一标识
    */
   void removeConfig(String miniappId);
 
   /**
-   * 注入多个 {@link WxMaConfig} 的实现. 并为每个 {@link WxMaConfig} 赋予不同的 {@link String mpId} 值 随机采用一个{@link
-   * String mpId}进行Http初始化操作
+   * 批量注入多个小程序配置信息。
    *
-   * @param configs WxMaConfig map
+   * @param configs          小程序配置Map，key为小程序标识
    */
   void setMultiConfigs(Map<String, WxMaConfig> configs);
 
   /**
-   * 注入多个 {@link WxMaConfig} 的实现. 并为每个 {@link WxMaConfig} 赋予不同的 {@link String label} 值
+   * 批量注入多个小程序配置信息，并指定默认小程序。
    *
-   * @param configs WxMaConfig map
-   * @param defaultMiniappId 设置一个{@link WxMaConfig} 所对应的{@link String defaultMiniappId}进行Http初始化
+   * @param configs          小程序配置Map，key为小程序标识
+   * @param defaultMiniappId 默认小程序标识
    */
   void setMultiConfigs(Map<String, WxMaConfig> configs, String defaultMiniappId);
 
   /**
-   * 进行相应的公众号切换.
+   * 切换到指定公众号。
    *
-   * @param mpId 公众号标识
-   * @return 切换是否成功 boolean
+   * @param mpId             公众号标识
+   * @return                 切换是否成功，true为成功，false为失败
    */
   boolean switchover(String mpId);
 
   /**
-   * 进行相应的小程序切换.
+   * 切换到指定小程序。
    *
-   * @param miniAppId 小程序标识
-   * @return 切换成功 ，则返回当前对象，方便链式调用，否则抛出异常
+   * @param miniAppId        小程序标识
+   * @return                 切换成功则返回当前对象，方便链式调用，否则抛出异常
    */
   WxMaService switchoverTo(String miniAppId);
 
   /**
-   * 进行相应的小程序切换.
+   * 切换到指定小程序，并在配置不存在时通过函数获取配置。
    *
-   * @param miniAppId 小程序标识
-   * @param func 当对应的小程序配置不存在时，允许通过函数的方式进行调用获取
-   * @return 切换成功 ，则返回当前对象，方便链式调用，否则抛出异常
+   * @param miniAppId        小程序标识
+   * @param func             获取配置的函数
+   * @return                 切换成功则返回当前对象，方便链式调用，否则抛出异常
    */
   WxMaService switchoverTo(String miniAppId, Function<String, WxMaConfig> func);
 
   /**
-   * 返回消息（客服消息和模版消息）发送接口方法实现类，以方便调用其各个接口.
+   * 获取消息（客服消息和模板消息）发送服务对象。
    *
-   * @return WxMaMsgService msg service
+   * @return                 消息服务对象WxMaMsgService
    */
   WxMaMsgService getMsgService();
 
   /**
-   * 返回素材相关接口方法的实现类对象，以方便调用其各个接口.
+   * 获取素材相关服务对象。
    *
-   * @return WxMaMediaService media service
+   * @return                 素材服务对象WxMaMediaService
    */
   WxMaMediaService getMediaService();
 
   /**
-   * 返回用户相关接口方法的实现类对象，以方便调用其各个接口.
+   * 获取用户相关服务对象。
    *
-   * @return WxMaUserService user service
+   * @return                 用户服务对象WxMaUserService
    */
   WxMaUserService getUserService();
 
   /**
-   * 返回二维码相关接口方法的实现类对象，以方便调用其各个接口.
+   * 获取二维码相关服务对象。
    *
-   * @return WxMaQrcodeService qrcode service
+   * @return                 二维码服务对象WxMaQrcodeService
    */
   WxMaQrcodeService getQrcodeService();
 
   /**
-   * 返回获取小程序scheme码实现对象，以方便调用其各个接口.
+   * 获取小程序scheme码服务对象。
    *
-   * @return WxMaSchemeService wx ma scheme service
+   * @return                 scheme码服务对象WxMaSchemeService
    */
   WxMaSchemeService getWxMaSchemeService();
 
   /**
-   * 返回订阅消息配置相关接口方法的实现类对象, 以方便调用其各个接口.
+   * 获取订阅消息配置相关服务对象。
    *
-   * @return WxMaSubscribeService subscribe service
+   * @return                 订阅消息服务对象WxMaSubscribeService
    */
   WxMaSubscribeService getSubscribeService();
 
   /**
-   * 数据分析相关查询服务.
+   * 获取数据分析相关服务对象。
    *
-   * @return WxMaAnalysisService analysis service
+   * @return                 数据分析服务对象WxMaAnalysisService
    */
   WxMaAnalysisService getAnalysisService();
 
   /**
-   * 返回代码操作相关的 API.
+   * 获取代码操作相关服务对象。
    *
-   * @return WxMaCodeService code service
+   * @return                 代码服务对象WxMaCodeService
    */
   WxMaCodeService getCodeService();
 
   /**
-   * 返回jsapi操作相关的 API服务类对象.
+   * 获取jsapi操作相关服务对象。
    *
-   * @return WxMaJsapiService jsapi service
+   * @return                 jsapi服务对象WxMaJsapiService
    */
   WxMaJsapiService getJsapiService();
 
   /**
-   * 小程序修改服务器地址、成员管理 API.
+   * 获取小程序服务器地址、成员管理相关服务对象。
    *
-   * @return WxMaSettingService setting service
+   * @return                 设置服务对象WxMaSettingService
    */
   WxMaSettingService getSettingService();
 
   /**
-   * 返回分享相关查询服务.
+   * 获取分享相关服务对象。
    *
-   * @return WxMaShareService share service
+   * @return                 分享服务对象WxMaShareService
    */
   WxMaShareService getShareService();
 
   /**
-   * 返回微信运动相关接口服务对象.
+   * 获取微信运动相关服务对象。
    *
-   * @return WxMaShareService run service
+   * @return                 微信运动服务对象WxMaRunService
    */
   WxMaRunService getRunService();
 
   /**
-   * 返回小程序安全相关接口服务对象.
+   * 获取小程序安全相关服务对象。
    *
-   * @return WxMaShareService sec check service
+   * @return                 安全服务对象WxMaSecurityService
    */
   WxMaSecurityService getSecurityService();
 
   /**
-   * 返回插件相关接口服务对象.
+   * 获取插件相关服务对象。
    *
-   * @return WxMaPluginService plugin service
+   * @return                 插件服务对象WxMaPluginService
    */
   WxMaPluginService getPluginService();
 
-  /** 初始化http请求对象. */
+  /**
+   * 初始化http请求对象。
+   */
   void initHttp();
 
   /**
-   * 请求http请求相关信息.
+   * 获取http请求相关信息。
    *
-   * @return . request http
+   * @return                 http请求对象RequestHttp
    */
-  RequestHttp getRequestHttp();
+  RequestHttp<?, ?> getRequestHttp();
 
   /**
-   * 获取物流助手接口服务对象
+   * 获取物流助手接口服务对象。
    *
-   * @return . express service
+   * @return                 物流助手服务对象WxMaExpressService
    */
   WxMaExpressService getExpressService();
 
   /**
-   * 获取云开发接口服务对象
+   * 获取云开发接口服务对象。
    *
-   * @return . cloud service
+   * @return                 云开发服务对象WxMaCloudService
    */
   WxMaCloudService getCloudService();
 
   /**
-   * 获取服务端网络接口服务对象
+   * 获取服务端网络接口服务对象。
    *
-   * @return 。internet service
+   * @return                 网络服务对象WxMaInternetService
    */
   WxMaInternetService getInternetService();
 
   /**
-   * 获取直播接口服务对象
+   * 获取直播接口服务对象。
    *
-   * @return . live service
+   * @return                 直播服务对象WxMaLiveService
    */
   WxMaLiveService getLiveService();
 
   /**
-   * 获取直播间商品服务对象
+   * 获取直播间商品服务对象。
    *
-   * @return . live goods service
+   * @return                 直播商品服务对象WxMaLiveGoodsService
    */
   WxMaLiveGoodsService getLiveGoodsService();
 
   /**
-   * 获取直播成员管理接口服务对象
+   * 获取直播成员管理接口服务对象。
    *
-   * @return . live service
+   * @return                 直播成员服务对象WxMaLiveMemberService
    */
   WxMaLiveMemberService getLiveMemberService();
 
   /**
-   * 获取ocr实现接口服务对象
+   * 获取OCR实现接口服务对象。
    *
-   * @return 。
+   * @return                 OCR服务对象WxOcrService
    */
   WxOcrService getOcrService();
 
   /**
-   * 返回图像处理接口的实现类对象，以方便调用其各个接口.
+   * 获取图像处理接口服务对象。
    *
-   * @return WxImgProcService img proc service
+   * @return                 图像处理服务对象WxImgProcService
    */
   WxImgProcService getImgProcService();
 
   /**
-   * 返回小程序交易组件-售后服务接口
+   * 获取小程序交易组件-售后服务接口服务对象。
    *
-   * @return
+   * @return                 售后服务对象WxMaShopAfterSaleService
    */
   WxMaShopAfterSaleService getShopAfterSaleService();
 
   /**
-   * 返回小程序交易组件-物流服务接口
+   * 获取小程序交易组件-物流服务接口服务对象。
    *
-   * @return
+   * @return                 物流服务对象WxMaShopDeliveryService
    */
   WxMaShopDeliveryService getShopDeliveryService();
 
   /**
-   * 返回小程序交易组件-订单服务接口
+   * 获取小程序交易组件-订单服务接口服务对象。
    *
-   * @return
+   * @return                 订单服务对象WxMaShopOrderService
    */
   WxMaShopOrderService getShopOrderService();
 
   /**
-   * 返回小程序交易组件-spu商品服务接口
+   * 获取小程序交易组件-spu商品服务接口服务对象。
    *
-   * @return
+   * @return                 spu商品服务对象WxMaShopSpuService
    */
   WxMaShopSpuService getShopSpuService();
 
   /**
-   * 返回小程序交易组件-接入申请接口
+   * 获取小程序交易组件-接入申请接口服务对象。
    *
-   * @return
+   * @return                 接入申请服务对象WxMaShopRegisterService
    */
   WxMaShopRegisterService getShopRegisterService();
 
   /**
-   * 返回小程序交易组件-商户入驻接口
+   * 获取小程序交易组件-商户入驻接口服务对象。
    *
-   * @return
+   * @return                 商户入驻服务对象WxMaShopAccountService
    */
   WxMaShopAccountService getShopAccountService();
 
   /**
-   * 小程序交易组件-接入商品前必需接口-类目相关
+   * 获取小程序交易组件-类目相关接口服务对象。
    *
-   * @return
+   * @return                 类目服务对象WxMaShopCatService
    */
   WxMaShopCatService getShopCatService();
 
   /**
-   * 小程序交易组件-接入商品前必需接口-上传图片
+   * 获取小程序交易组件-上传图片接口服务对象。
    *
-   * @return
+   * @return                 图片服务对象WxMaShopImgService
    */
   WxMaShopImgService getShopImgService();
 
   /**
-   * 小程序交易组件-接入商品前必需接口-审核相关接口
+   * 获取小程序交易组件-审核相关接口服务对象。
    *
-   * @return
+   * @return                 审核服务对象WxMaShopAuditService
    */
   WxMaShopAuditService getShopAuditService();
 
   /**
-   * 获取小程序Link服务接口
+   * 获取小程序Link服务接口服务对象。
    *
-   * @return
+   * @return                 Link服务对象WxMaLinkService
    */
   WxMaLinkService getLinkService();
 
   /**
-   * 获取电子发票报销方服务接口
+   * 获取电子发票报销方服务接口服务对象。
    *
-   * @return
+   * @return                 电子发票报销方服务对象WxMaReimburseInvoiceService
    */
   WxMaReimburseInvoiceService getReimburseInvoiceService();
 
   /**
-   * 返回设备订阅消息相关接口服务对象
+   * 获取设备订阅消息相关接口服务对象。
    *
-   * @return WxMaDeviceSubscribeService plugin service
+   * @return                 设备订阅消息服务对象WxMaDeviceSubscribeService
    */
   WxMaDeviceSubscribeService getDeviceSubscribeService();
 
   /**
-   * 返回小程序广告接入相关接口服务对象
+   * 获取小程序广告接入相关接口服务对象。
    *
-   * @return WxMaDeviceSubscribeService plugin service
+   * @return                 广告服务对象WxMaMarketingService
    */
   WxMaMarketingService getMarketingService();
 
   /**
-   * 返回微信小程序即时配送服务接口.
+   * 获取微信小程序即时配送服务接口服务对象。
    *
-   * @return WxMaImmediateDeliveryService
+   * @return                 即时配送服务对象WxMaImmediateDeliveryService
    */
   WxMaImmediateDeliveryService getWxMaImmediateDeliveryService();
 
   /**
-   * 分享人接口
+   * 获取小程序分享人接口服务对象。
    *
-   * @return WxMaShopSharerService
+   * @return                 分享人服务对象WxMaShopSharerService
    */
   WxMaShopSharerService getShopSharerService();
 
   /**
-   * 标准交易组件接口
+   * 获取标准交易组件接口服务对象。
    *
-   * @return WxMaProductService
+   * @return                 标准交易组件服务对象WxMaProductService
    */
   WxMaProductService getProductService();
 
   /**
-   * 小商店-标准交易组件-订单服务
+   * 获取小商店-标准交易组件-订单服务对象。
    *
-   * @return getProductOrderService
+   * @return                 订单服务对象WxMaProductOrderService
    */
   WxMaProductOrderService getProductOrderService();
 
   /**
-   * 小商店-标准交易组件-优惠券
+   * 获取小商店-标准交易组件-优惠券服务对象。
    *
-   * @return getWxMaShopCouponService
+   * @return                 优惠券服务对象WxMaShopCouponService
    */
   WxMaShopCouponService getWxMaShopCouponService();
 
   /**
-   * 小程序支付管理-订单支付
+   * 获取小程序支付管理-订单支付服务对象。
    *
-   * @return getWxMaShopPayService
+   * @return                 订单支付服务对象WxMaShopPayService
    */
   WxMaShopPayService getWxMaShopPayService();
 
   /**
-   * 小程序发货信息管理服务
+   * 获取小程序发货信息管理服务对象。
    *
-   * @return getWxMaOrderShippingService
+   * @return                 发货信息管理服务对象WxMaOrderShippingService
    */
   WxMaOrderShippingService getWxMaOrderShippingService();
 
   /**
-   * 小程序openApi管理
+   * 获取小程序订单管理服务对象。
    *
-   * @return getWxMaOpenApiService
+   * @return                 订单管理服务对象WxMaOrderManagementService
+   */
+  WxMaOrderManagementService getWxMaOrderManagementService();
+
+  /**
+   * 获取小程序openApi管理服务对象。
+   *
+   * @return                 openApi管理服务对象WxMaOpenApiService
    */
   WxMaOpenApiService getWxMaOpenApiService();
 
   /**
-   * 小程序短剧管理
+   * 获取小程序短剧管理服务对象。
    *
-   * @return getWxMaVodService
+   * @return                 短剧管理服务对象WxMaVodService
    */
   WxMaVodService getWxMaVodService();
 
   /**
-   * 小程序虚拟支付
+   * 获取小程序虚拟支付服务对象。
    *
-   * @return getWxMaXPayService
+   * @return                 虚拟支付服务对象WxMaXPayService
    */
   WxMaXPayService getWxMaXPayService();
 
+  /**
+   * 获取小程序物流退货服务对象。
+   *
+   * @return                 物流退货服务对象WxMaExpressDeliveryReturnService
+   */
   WxMaExpressDeliveryReturnService getWxMaExpressDeliveryReturnService();
 
   /**
-   * 小程序推广员
+   * 获取小程序推广员服务对象。
    *
-   * @return WxMaPromotionService
+   * @return                 推广员服务对象WxMaPromotionService
    */
   WxMaPromotionService getWxMaPromotionService();
 
+  /**
+   * 以签名方式POST数据到指定URL。
+   *
+   * @param url              请求地址
+   * @param obj              请求对象
+   * @return                 微信接口响应字符串
+   * @throws WxErrorException 微信接口调用异常
+   */
   String postWithSignature(String url, Object obj) throws WxErrorException;
 
+  /**
+   * 以签名方式POST数据到指定URL。
+   *
+   * @param url              请求地址
+   * @param jsonObject       请求的Json对象
+   * @return                 微信接口响应字符串
+   * @throws WxErrorException 微信接口调用异常
+   */
   String postWithSignature(String url, JsonObject jsonObject) throws WxErrorException;
 
   /**
-   * 微信物流服务 -- 同城配送
-   * https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/industry/express/business/intracity_service.html
+   * 获取微信物流服务--同城配送服务对象。
+   * <br>
+   * 文档：https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/industry/express/business/intracity_service.html
+   *
+   * @return                 同城配送服务对象WxMaIntracityService
    */
   WxMaIntracityService getIntracityService();
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaVodService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaVodService.java
index 547d280962..217a699c5a 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaVodService.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaVodService.java
@@ -6,39 +6,181 @@
 import java.io.File;
 import java.util.List;
 
+/**
+ * 小程序短剧管理服务接口。
+ * 提供短剧视频上传、管理、审核、播放等相关功能。
+ * 文档：https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/vod.html
+ *
+ */
 public interface WxMaVodService {
+
+  /**
+   * 获取媒体列表。
+   * 分页获取已上传的媒体文件列表。
+   *
+   * @param request          获取媒体列表请求对象
+   * @return                 媒体信息列表
+   * @throws WxErrorException 获取失败时抛出
+   */
   List<WxMaVodMediaInfo> listMedia(WxMaVodListMediaRequest request) throws WxErrorException;
 
+  /**
+   * 获取剧集列表。
+   * 分页获取已创建的剧集列表。
+   *
+   * @param request          获取剧集列表请求对象
+   * @return                 剧集信息列表
+   * @throws WxErrorException 获取失败时抛出
+   */
   List<WxMaVodDramaInfo> listDrama(WxMaVodListDramaRequest request) throws WxErrorException;
 
+  /**
+   * 获取媒体播放链接。
+   * 获取指定媒体文件的播放地址和相关信息。
+   *
+   * @param request          获取媒体播放链接请求对象
+   * @return                 媒体播放信息对象
+   * @throws WxErrorException 获取失败时抛出
+   */
   WxMaVodMediaPlaybackInfo getMediaLink(WxMaVodGetMediaLinkRequest request) throws WxErrorException;
 
+  /**
+   * 获取媒体详情。
+   * 获取指定媒体文件的详细信息。
+   *
+   * @param request          获取媒体详情请求对象
+   * @return                 媒体信息对象
+   * @throws WxErrorException 获取失败时抛出
+   */
   WxMaVodMediaInfo getMedia(WxMaVodGetMediaRequest request) throws WxErrorException;
 
+  /**
+   * 删除媒体文件。
+   * 删除指定的媒体文件，删除后无法恢复。
+   *
+   * @param request          删除媒体请求对象
+   * @return                 删除是否成功
+   * @throws WxErrorException 删除失败时抛出
+   */
   boolean deleteMedia(WxMaVodDeleteMediaRequest request) throws WxErrorException;
 
+  /**
+   * 获取剧集详情。
+   * 获取指定剧集的详细信息。
+   *
+   * @param request          获取剧集详情请求对象
+   * @return                 剧集信息对象
+   * @throws WxErrorException 获取失败时抛出
+   */
   WxMaVodDramaInfo getDrama(WxMaVodGetDramaRequest request) throws WxErrorException;
 
+  /**
+   * 审核剧集。
+   * 提交剧集进行内容审核。
+   *
+   * @param request          审核剧集请求对象
+   * @return                 审核任务ID
+   * @throws WxErrorException 审核提交失败时抛出
+   */
   Integer auditDrama(WxMaVodAuditDramaRequest request) throws WxErrorException;
 
+  /**
+   * 获取CDN用量数据。
+   * 查询指定时间段内的CDN流量使用情况。
+   *
+   * @param request          获取CDN用量请求对象
+   * @return                 CDN用量数据响应对象
+   * @throws WxErrorException 获取失败时抛出
+   */
   WxMaVodGetCdnUsageResponse getCdnUsageData(WxMaVodGetCdnUsageRequest request) throws WxErrorException;
 
+  /**
+   * 获取CDN日志。
+   * 获取指定时间段内的CDN访问日志。
+   *
+   * @param request          获取CDN日志请求对象
+   * @return                 CDN日志响应对象
+   * @throws WxErrorException 获取失败时抛出
+   */
   WxMaVodGetCdnLogResponse getCdnLogs(WxMaVodGetCdnLogRequest request) throws WxErrorException;
 
-
+  /**
+   * 拉取上传。
+   * 通过URL拉取视频文件到平台进行上传。
+   *
+   * @param request          拉取上传请求对象
+   * @return                 拉取上传响应对象
+   * @throws WxErrorException 拉取失败时抛出
+   */
   WxMaVodPullUploadResponse pullUpload(WxMaVodPullUploadRequest request) throws WxErrorException;
 
+  /**
+   * 获取任务状态。
+   * 查询异步任务的执行状态和结果。
+   *
+   * @param request          获取任务状态请求对象
+   * @return                 任务状态响应对象
+   * @throws WxErrorException 获取失败时抛出
+   */
   WxMaVodGetTaskResponse getTask(WxMaVodGetTaskRequest request) throws WxErrorException;
 
-
+  /**
+   * 单文件上传（简化版）。
+   * 直接上传单个视频文件到平台。
+   *
+   * @param file             要上传的文件
+   * @param mediaName        媒体文件名称
+   * @param mediaType        媒体文件类型
+   * @return                 单文件上传结果
+   * @throws WxErrorException 上传失败时抛出
+   */
   WxMaVodSingleFileUploadResult uploadSingleFile(File file, String mediaName, String mediaType) throws WxErrorException;
 
+  /**
+   * 单文件上传（完整版）。
+   * 上传视频文件和封面图片到平台。
+   *
+   * @param file             要上传的视频文件
+   * @param mediaName        媒体文件名称
+   * @param mediaType        媒体文件类型
+   * @param coverType        封面图片类型
+   * @param coverData        封面图片文件
+   * @param sourceContext    来源上下文信息
+   * @return                 单文件上传结果
+   * @throws WxErrorException 上传失败时抛出
+   */
   WxMaVodSingleFileUploadResult uploadSingleFile(File file, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) throws WxErrorException;
 
+  /**
+   * 申请上传。
+   * 申请分片上传的上传凭证和上传地址。
+   *
+   * @param request          申请上传请求对象
+   * @return                 申请上传响应对象
+   * @throws WxErrorException 申请失败时抛出
+   */
   WxMaVodApplyUploadResponse applyUpload(WxMaVodApplyUploadRequest request) throws WxErrorException;
 
+  /**
+   * 确认上传。
+   * 确认分片上传完成，合并所有分片文件。
+   *
+   * @param request          确认上传请求对象
+   * @return                 确认上传响应对象
+   * @throws WxErrorException 确认失败时抛出
+   */
   WxMaVodCommitUploadResponse commitUpload(WxMaVodCommitUploadRequest request) throws WxErrorException;
 
+  /**
+   * 上传分片。
+   * 上传文件的一个分片。
+   *
+   * @param file             分片文件
+   * @param uploadId         上传ID
+   * @param partNumber       分片编号
+   * @param resourceType     资源类型
+   * @return                 分片上传结果
+   * @throws WxErrorException 上传失败时抛出
+   */
   WxMaVodUploadPartResult uploadPart(File file, String uploadId, Integer partNumber, Integer resourceType) throws WxErrorException;
-
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaXPayService.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaXPayService.java
index a099cd6dd7..a633c93de6 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaXPayService.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaXPayService.java
@@ -1,37 +1,305 @@
 package cn.binarywang.wx.miniapp.api;
 
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
 import cn.binarywang.wx.miniapp.bean.xpay.*;
 import me.chanjar.weixin.common.error.WxErrorException;
 
+/**
+ * 小程序虚拟支付相关接口。
+ * 文档：https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/industry/virtual-payment.html
+ *
+ */
 public interface WxMaXPayService {
 
+  /**
+   * 查询用户虚拟币余额。
+   *
+   * @param request          查询用户余额请求对象
+   * @param sigParams        签名参数对象
+   * @return                 用户余额查询结果
+   * @throws WxErrorException 查询失败时抛出
+   */
   WxMaXPayQueryUserBalanceResponse queryUserBalance(WxMaXPayQueryUserBalanceRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
 
+  /**
+   * 虚拟币充值下单。
+   *
+   * @param request          虚拟币充值请求对象
+   * @param sigParams        签名参数对象
+   * @return                 虚拟币充值结果
+   * @throws WxErrorException 充值失败时抛出
+   */
   WxMaXPayCurrencyPayResponse currencyPay(WxMaXPayCurrencyPayRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
 
+  /**
+   * 查询订单信息。
+   *
+   * @param request          查询订单请求对象
+   * @param sigParams        签名参数对象
+   * @return                 订单查询结果
+   * @throws WxErrorException 查询失败时抛出
+   */
   WxMaXPayQueryOrderResponse queryOrder(WxMaXPayQueryOrderRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
 
+  /**
+   * 取消虚拟币充值订单。
+   *
+   * @param request          取消充值订单请求对象
+   * @param sigParams        签名参数对象
+   * @return                 取消充值订单结果
+   * @throws WxErrorException 取消失败时抛出
+   */
   WxMaXPayCancelCurrencyPayResponse cancelCurrencyPay(WxMaXPayCancelCurrencyPayRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
 
+  /**
+   * 通知发货。
+   *
+   * @param request          通知发货请求对象
+   * @param sigParams        签名参数对象
+   * @return                 通知发货是否成功
+   * @throws WxErrorException 通知失败时抛出
+   */
   boolean notifyProvideGoods(WxMaXPayNotifyProvideGoodsRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
 
+  /**
+   * 赠送虚拟币。
+   *
+   * @param request          赠送虚拟币请求对象
+   * @param sigParams        签名参数对象
+   * @return                 赠送虚拟币结果
+   * @throws WxErrorException 赠送失败时抛出
+   */
   WxMaXPayPresentCurrencyResponse presentCurrency(WxMaXPayPresentCurrencyRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
 
-
+  /**
+   * 下载对账单。
+   *
+   * @param request          下载对账单请求对象
+   * @param sigParams        签名参数对象
+   * @return                 对账单下载结果
+   * @throws WxErrorException 下载失败时抛出
+   */
   WxMaXPayDownloadBillResponse downloadBill(WxMaXPayDownloadBillRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
 
+  /**
+   * 退款申请。
+   *
+   * @param request          退款申请请求对象
+   * @param sigParams        签名参数对象
+   * @return                 退款申请结果
+   * @throws WxErrorException 退款失败时抛出
+   */
   WxMaXPayRefundOrderResponse refundOrder(WxMaXPayRefundOrderRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
 
+  /**
+   * 创建提现订单。
+   *
+   * @param request          创建提现订单请求对象
+   * @param sigParams        签名参数对象
+   * @return                 创建提现订单结果
+   * @throws WxErrorException 创建失败时抛出
+   */
   WxMaXPayCreateWithdrawOrderResponse createWithdrawOrder(WxMaXPayCreateWithdrawOrderRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
 
+  /**
+   * 查询提现订单。
+   *
+   * @param request          查询提现订单请求对象
+   * @param sigParams        签名参数对象
+   * @return                 提现订单查询结果
+   * @throws WxErrorException 查询失败时抛出
+   */
   WxMaXPayQueryWithdrawOrderResponse queryWithdrawOrder(WxMaXPayQueryWithdrawOrderRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
 
+  /**
+   * 启动道具上传。
+   *
+   * @param request          启动道具上传请求对象
+   * @param sigParams        签名参数对象
+   * @return                 启动道具上传是否成功
+   * @throws WxErrorException 启动失败时抛出
+   */
   boolean startUploadGoods(WxMaXPayStartUploadGoodsRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
 
+  /**
+   * 查询道具上传状态。
+   *
+   * @param request          查询道具上传状态请求对象
+   * @param sigParams        签名参数对象
+   * @return                 道具上传状态查询结果
+   * @throws WxErrorException 查询失败时抛出
+   */
   WxMaXPayQueryUploadGoodsResponse queryUploadGoods(WxMaXPayQueryUploadGoodsRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
 
+  /**
+   * 启动道具发布。
+   *
+   * @param request          启动道具发布请求对象
+   * @param sigParams        签名参数对象
+   * @return                 启动道具发布是否成功
+   * @throws WxErrorException 启动失败时抛出
+   */
   boolean startPublishGoods(WxMaXPayStartPublishGoodsRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
 
+  /**
+   * 查询道具发布状态。
+   *
+   * @param request          查询道具发布状态请求对象
+   * @param sigParams        签名参数对象
+   * @return                 道具发布状态查询结果
+   * @throws WxErrorException 查询失败时抛出
+   */
   WxMaXPayQueryPublishGoodsResponse queryPublishGoods(WxMaXPayQueryPublishGoodsRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
 
+  /**
+   * 查询商家账户里的可提现余额。
+   *
+   * @param request   查询商家账户里的可提现余额请求对象
+   * @param sigParams 签名参数对象
+   * @return 商家账户里的可提现余额查询结果
+   * @throws WxErrorException 查询失败时抛出
+   */
+  WxMaXPayQueryBizBalanceResponse queryBizBalance(WxMaXPayQueryBizBalanceRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+  /**
+   * 查询广告金充值账户。
+   *
+   * @param request   查询广告金充值账户请求对象
+   * @param sigParams 签名参数对象
+   * @return 广告金充值账户查询结果
+   * @throws WxErrorException 查询失败时抛出
+   */
+  WxMaXPayQueryTransferAccountResponse queryTransferAccount(WxMaXPayQueryTransferAccountRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+  /**
+   * 查询广告金发放记录。
+   *
+   * @param request   查询广告金发放记录请求对象
+   * @param sigParams 签名参数对象
+   * @return 查询广告金发放记录结果
+   * @throws WxErrorException 查询失败时抛出
+   */
+  WxMaXPayQueryAdverFundsResponse queryAdverFunds(WxMaXPayQueryAdverFundsRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+  /**
+   * 充值广告金。
+   *
+   * @param request   充值广告金请求对象
+   * @param sigParams 签名参数对象
+   * @return 充值广告金结果
+   * @throws WxErrorException 查询失败时抛出
+   */
+  WxMaXPayCreateFundsBillResponse createFundsBill(WxMaXPayCreateFundsBillRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+  /**
+   * 绑定广告金充值账户。
+   *
+   * @param request   绑定广告金充值账户请求对象
+   * @param sigParams 签名参数对象
+   * @return 绑定广告金充值账户结果
+   * @throws WxErrorException 查询失败时抛出
+   */
+  WxMaBaseResponse bindTransferAccount(WxMaXPayBindTransferAccountRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+  /**
+   * 查询广告金充值记录。
+   *
+   * @param request   查询广告金充值记录请求对象
+   * @param sigParams 签名参数对象
+   * @return 查询广告金充值记录结果
+   * @throws WxErrorException 查询失败时抛出
+   */
+  WxMaXPayQueryFundsBillResponse queryFundsBill(WxMaXPayQueryFundsBillRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+  /**
+   * 查询广告金回收记录。
+   *
+   * @param request   查询广告金回收记录请求对象
+   * @param sigParams 签名参数对象
+   * @return 查询广告金回收记录结果
+   * @throws WxErrorException 查询失败时抛出
+   */
+  WxMaXPayQueryRecoverBillResponse queryRecoverBill(WxMaXPayQueryRecoverBillRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+
+ /**
+   * 获取投诉列表。
+   *
+   * @param request          获取投诉列表请求对象
+   * @param sigParams        签名参数对象
+   * @return                 获取投诉列表结果
+   * @throws WxErrorException 查询失败时抛出
+   */
+  WxMaXPayGetComplaintListResponse getComplaintList(WxMaXPayGetComplaintListRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+ /**
+   * 获取投诉详情。
+   *
+   * @param request          获取投诉详情请求对象
+   * @param sigParams        签名参数对象
+   * @return                 获取投诉详情结果
+   * @throws WxErrorException 查询失败时抛出
+   */
+  WxMaXPayGetComplaintDetailResponse getComplaintDetail(WxMaXPayGetComplaintDetailRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+ /**
+   * 获取协商历史。
+   *
+   * @param request          获取协商历史请求对象
+   * @param sigParams        签名参数对象
+   * @return                 获取协商历史结果
+   * @throws WxErrorException 查询失败时抛出
+   */
+  WxMaXPayGetNegotiationHistoryResponse getNegotiationHistory(WxMaXPayGetNegotiationHistoryRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+ /**
+   * 回复用户。
+   *
+   * @param request          回复用户请求对象
+   * @param sigParams        签名参数对象
+   * @return                 回复用户结果
+   * @throws WxErrorException 查询失败时抛出
+   */
+  WxMaBaseResponse responseComplaint(WxMaXPayResponseComplaintRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+ /**
+   * 完成投诉处理。
+   *
+   * @param request          完成投诉处理请求对象
+   * @param sigParams        签名参数对象
+   * @return                 完成投诉处理结果
+   * @throws WxErrorException 查询失败时抛出
+   */
+ WxMaBaseResponse completeComplaint(WxMaXPayCompleteComplaintRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+ /**
+   * 上传媒体文件（如图片，凭证等）。
+   *
+   * @param request          上传媒体文件（如图片，凭证等）请求对象
+   * @param sigParams        签名参数对象
+   * @return                 上传媒体文件（如图片，凭证等）结果
+   * @throws WxErrorException 查询失败时抛出
+   */
+  WxMaXPayUploadVpFileResponse uploadVpFile(WxMaXPayUploadVpFileRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+ /**
+   * 获取微信支付反馈投诉图片的签名头部。
+   *
+   * @param request          获取微信支付反馈投诉图片的签名头部请求对象
+   * @param sigParams        签名参数对象
+   * @return                 获取微信支付反馈投诉图片的签名头部结果
+   * @throws WxErrorException 查询失败时抛出
+   */
+  WxMaXPayGetUploadFileSignResponse getUploadFileSign(WxMaXPayGetUploadFileSignRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
+ /**
+   * 下载广告金对应的商户订单信息。
+   *
+   * @param request          下载广告金对应的商户订单信息请求对象
+   * @param sigParams        签名参数对象
+   * @return                 下载广告金对应的商户订单信息结果
+   * @throws WxErrorException 查询失败时抛出
+   */
+  WxMaXPayDownloadAdverfundsOrderResponse downloadAdverfundsOrder(WxMaXPayDownloadAdverfundsOrderRequest request, WxMaXPaySigParams sigParams) throws WxErrorException;
+
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java
index 9385cad462..4a5ca19274 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/BaseWxMaServiceImpl.java
@@ -38,6 +38,7 @@
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxMaErrorMsgEnum;
 import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.executor.CommonUploadRequestExecutor;
 import me.chanjar.weixin.common.service.WxImgProcService;
@@ -153,6 +154,9 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
   private final WxMaOrderShippingService wxMaOrderShippingService =
       new WxMaOrderShippingServiceImpl(this);
 
+  private final WxMaOrderManagementService wxMaOrderManagementService =
+      new WxMaOrderManagementServiceImpl(this);
+
   private final WxMaOpenApiService wxMaOpenApiService = new WxMaOpenApiServiceImpl(this);
   private final WxMaVodService wxMaVodService = new WxMaVodServiceImpl(this);
   private final WxMaXPayService wxMaXPayService = new WxMaXPayServiceImpl(this);
@@ -166,7 +170,7 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
   private int maxRetryTimes = 5;
 
   @Override
-  public RequestHttp getRequestHttp() {
+  public RequestHttp<H, P> getRequestHttp() {
     return this;
   }
 
@@ -229,7 +233,7 @@ public boolean checkSignature(String timestamp, String nonce, String signature)
     try {
       return SHA1.gen(this.getWxMaConfig().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;
     }
   }
@@ -294,7 +298,7 @@ public String get(String url, String queryParam) throws WxErrorException {
 
   private boolean isApiSignatureRequired(String url) {
     return this.getWxMaConfig().getApiSignatureAesKey() != null
-        && Arrays.stream(urlPathSupportApiSignature).anyMatch(part -> url.contains(part));
+        && Arrays.stream(urlPathSupportApiSignature).anyMatch(url::contains);
   }
 
   @Override
@@ -358,7 +362,7 @@ public <R, T> R execute(RequestExecutor<R, T> executor, String uri, T data)
 
   @Override
   public WxMaApiResponse execute(
-      ApiSignaturePostRequestExecutor executor,
+      ApiSignaturePostRequestExecutor<?, ?> executor,
       String uri,
       Map<String, String> headers,
       String data)
@@ -455,7 +459,12 @@ private <R, T> R executeInternal(
       }
 
       if (error.getErrorCode() != 0) {
-        log.warn("\n【请求地址】: {}\n【请求参数】：{}\n【错误信息】：{}", uriWithAccessToken, dataForLog, error);
+        if (error.getErrorCode() == WxMaErrorMsgEnum.CODE_43101.getCode()) {
+          // 43101 日志太多, 打印为debug, 其他情况打印为warn
+          log.debug("\n【请求地址】: {}\n【请求参数】：{}\n【错误信息】：{}", uriWithAccessToken, dataForLog, error);
+        } else {
+          log.warn("\n【请求地址】: {}\n【请求参数】：{}\n【错误信息】：{}", uriWithAccessToken, dataForLog, error);
+        }
         throw new WxErrorException(error, e);
       }
       return null;
@@ -499,7 +508,10 @@ public WxMaConfig getWxMaConfig() {
   @Override
   public void setWxMaConfig(WxMaConfig maConfig) {
     final String appid = maConfig.getAppid();
-    this.setMultiConfigs(ImmutableMap.of(appid, maConfig), appid);
+    Map<String, WxMaConfig> map = new HashMap<>();
+    map.put(appid, maConfig);
+    Map<String, WxMaConfig> configMap = Collections.unmodifiableMap(map);
+    this.setMultiConfigs(configMap, appid);
   }
 
   @Override
@@ -814,6 +826,16 @@ public WxMaOrderShippingService getWxMaOrderShippingService() {
     return this.wxMaOrderShippingService;
   }
 
+  /**
+   * 小程序订单管理服务
+   *
+   * @return WxMaOrderManagementService
+   */
+  @Override
+  public WxMaOrderManagementService getWxMaOrderManagementService() {
+    return this.wxMaOrderManagementService;
+  }
+
   @Override
   public WxMaOpenApiService getWxMaOpenApiService() {
     return this.wxMaOpenApiService;
@@ -882,6 +904,7 @@ public String postWithSignature(String url, JsonObject jsonObject) throws WxErro
     jsonObject.addProperty("_timestamp", timestamp);
 
     String plainText = jsonObject.toString();
+    log.debug("URL:{}加密前请求数据:{}", url, plainText);
     String urlPath;
     if (url.contains("?")) {
       urlPath = url.substring(0, url.indexOf("?"));
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaCloudServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaCloudServiceImpl.java
index 3e16814479..45c7339bc9 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaCloudServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaCloudServiceImpl.java
@@ -55,7 +55,7 @@ public String invokeCloudFunction(String env, String name, String body) throws W
   }
 
   @Override
-  public List<String> add(String collection, List list) throws WxErrorException {
+  public List<String> add(String collection, List<?> list) throws WxErrorException {
     String jsonData = WxMaGsonBuilder.create().toJson(list);
     String query = blankJoiner.join(
       "db.collection('", collection, "')",
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaDeviceSubscribeServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaDeviceSubscribeServiceImpl.java
index 0943a1feeb..7f8dce1df8 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaDeviceSubscribeServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaDeviceSubscribeServiceImpl.java
@@ -4,7 +4,6 @@
 import cn.binarywang.wx.miniapp.api.WxMaService;
 import cn.binarywang.wx.miniapp.bean.device.WxMaDeviceSubscribeMessageRequest;
 import cn.binarywang.wx.miniapp.bean.device.WxMaDeviceTicketRequest;
-import cn.binarywang.wx.miniapp.constant.WxMaConstants;
 import com.google.gson.JsonObject;
 import lombok.RequiredArgsConstructor;
 import me.chanjar.weixin.common.api.WxConsts;
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaImmediateDeliveryServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaImmediateDeliveryServiceImpl.java
index 05e8f2e0a7..910eb19d22 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaImmediateDeliveryServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaImmediateDeliveryServiceImpl.java
@@ -5,7 +5,6 @@
 import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
 import cn.binarywang.wx.miniapp.bean.delivery.*;
 import cn.binarywang.wx.miniapp.bean.delivery.base.WxMaDeliveryBaseResponse;
-import cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants;
 import cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.InstantDelivery;
 import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
 import com.google.gson.JsonElement;
@@ -207,7 +206,7 @@ public GetDeliveryListResponse getDeliveryList() throws WxErrorException {
 
   @Override
   public WxMaBaseResponse updateWaybillGoods(UpdateWaybillGoodsRequest request) throws WxErrorException {
-    String responseContent = this.wxMaService.post(InstantDelivery.GET_DELIVERY_LIST_URL,request);
+    String responseContent = this.wxMaService.post(InstantDelivery.UPDATE_WAYBILL_GOODS_URL,request);
     WxMaBaseResponse response = WxMaGsonBuilder.create().fromJson(responseContent, WxMaBaseResponse.class);
     if (response.getErrcode() == -1) {
       throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp));
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaInternetServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaInternetServiceImpl.java
index f42564279a..7da44ddaba 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaInternetServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaInternetServiceImpl.java
@@ -12,6 +12,7 @@
 
 import javax.crypto.Mac;
 import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
 
 /**
  * 服务端网络相关接口
@@ -25,9 +26,9 @@ public class WxMaInternetServiceImpl implements WxMaInternetService {
 
   private String sha256(String data, String sessionKey) throws Exception {
     Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
-    SecretKeySpec secret_key = new SecretKeySpec(sessionKey.getBytes("UTF-8"), "HmacSHA256");
+    SecretKeySpec secret_key = new SecretKeySpec(sessionKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
     sha256_HMAC.init(secret_key);
-    byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
+    byte[] array = sha256_HMAC.doFinal(data.getBytes(StandardCharsets.UTF_8));
     StringBuilder sb = new StringBuilder();
     for (byte item : array) {
       sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaIntracityServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaIntracityServiceImpl.java
index 46a728eca9..3e21dab79f 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaIntracityServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaIntracityServiceImpl.java
@@ -205,9 +205,10 @@ public WxMaGetPayModeResponse getPayMode() throws WxErrorException {
   }
 
   @Override
-  public WxMaAddOrderResponse preAddOrder(WxMaPreAddOrderRequest request) throws WxErrorException {
+  public WxMaPreAddOrderResponse preAddOrder(WxMaPreAddOrderRequest request)
+      throws WxErrorException {
     String response = this.wxMaService.postWithSignature(Intracity.PRE_ADD_ORDER, request);
-    return gson.fromJson(response, WxMaAddOrderResponse.class);
+    return gson.fromJson(response, WxMaPreAddOrderResponse.class);
   }
 
   @Override
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaLiveGoodsServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaLiveGoodsServiceImpl.java
index cfd8428673..4f9d3be175 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaLiveGoodsServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaLiveGoodsServiceImpl.java
@@ -21,7 +21,6 @@
 import java.util.Map;
 
 import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Broadcast.Goods.*;
-import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Code.GET_PAGE_URL;
 
 /**
  * <pre>
@@ -82,7 +81,7 @@ public WxMaLiveResult getApprovedGoods(Integer offset, Integer limit, Integer st
     String responseContent = wxMaService.get(GET_APPROVED_GOODS, Joiner.on("&").withKeyValueSeparator("=").join(params));
     JsonObject jsonObject = GsonParser.parse(responseContent);
     JsonArray goodsArr = jsonObject.getAsJsonArray("goods");
-    if (goodsArr.size() > 0) {
+    if (!goodsArr.isEmpty()) {
       for (int i = 0; i < goodsArr.size(); i++) {
         // 接口返回key是驼峰
         JsonObject goods = (JsonObject) goodsArr.get(i);
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java
index eaf23f11e9..d84603a53b 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaMsgServiceImpl.java
@@ -6,7 +6,6 @@
 import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
 import cn.binarywang.wx.miniapp.bean.WxMaUniformMessage;
 import cn.binarywang.wx.miniapp.bean.WxMaUpdatableMsg;
-import cn.binarywang.wx.miniapp.constant.WxMaConstants;
 import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
 import com.google.gson.JsonObject;
 import lombok.RequiredArgsConstructor;
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaOrderManagementServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaOrderManagementServiceImpl.java
new file mode 100644
index 0000000000..27d7c01487
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaOrderManagementServiceImpl.java
@@ -0,0 +1,71 @@
+package cn.binarywang.wx.miniapp.api.impl;
+
+import cn.binarywang.wx.miniapp.api.WxMaOrderManagementService;
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.bean.order.WxMaOrderManagementGetOrderDetailPath;
+import cn.binarywang.wx.miniapp.bean.order.WxMaOrderManagementResult;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.JsonObject;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.api.WxConsts;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.json.GsonHelper;
+import me.chanjar.weixin.common.util.json.GsonParser;
+
+import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.OrderManagement.*;
+
+
+/**
+ * @author xzh
+ * @Description
+ * @createTime 2025/01/16 15:31
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class WxMaOrderManagementServiceImpl implements WxMaOrderManagementService {
+
+  private final WxMaService wxMaService;
+
+  /**
+   * 查询订单详情路径
+   * 注意事项
+   * 如果没有配置过订单详情路径，会返回成功，其中path为''。
+   *
+   * @return WxMaOrderManagementGetOrderDetailPath
+   * @throws WxErrorException e
+   */
+  @Override
+  public WxMaOrderManagementGetOrderDetailPath getOrderDetailPath() throws WxErrorException {
+    return request(GET_ORDER_DETAIL_PATH, new Object(), WxMaOrderManagementGetOrderDetailPath.class);
+
+  }
+
+  /**
+   * 配置订单详情路径
+   * 注意事项
+   * 调用接口前需要先完成订单中心授权协议签署。
+   * 请确保配置的path可正常跳转到小程序，并且path必须包含字符串“${商品订单号}”。
+   *
+   * @param path 订单详情路径
+   * @return WxMaOrderManagementResult
+   * @throws WxErrorException e
+   */
+  @Override
+  public WxMaOrderManagementResult updateOrderDetailPath(String path) throws WxErrorException {
+    JsonObject jsonObject = GsonHelper.buildJsonObject("path", path);
+    return request(UPDATE_ORDER_DETAIL_PATH, jsonObject, WxMaOrderManagementResult.class);
+
+  }
+
+  private <T> T request(String url, Object request, Class<T> resultT) throws WxErrorException {
+    String responseContent = this.wxMaService.post(url, request);
+    JsonObject jsonObject = GsonParser.parse(responseContent);
+    if (jsonObject.get(WxConsts.ERR_CODE).getAsInt() != 0) {
+      throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp));
+    }
+    return WxMaGsonBuilder.create().fromJson(responseContent, resultT);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaOrderShippingServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaOrderShippingServiceImpl.java
index 4aee53e15d..1627a27cd0 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaOrderShippingServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaOrderShippingServiceImpl.java
@@ -4,10 +4,7 @@
 import cn.binarywang.wx.miniapp.api.WxMaService;
 import cn.binarywang.wx.miniapp.bean.shop.request.WxMaOrderShippingIsTradeManagedRequest;
 import cn.binarywang.wx.miniapp.bean.shop.request.shipping.*;
-import cn.binarywang.wx.miniapp.bean.shop.response.WxMaOrderShippingInfoBaseResponse;
-import cn.binarywang.wx.miniapp.bean.shop.response.WxMaOrderShippingInfoGetListResponse;
-import cn.binarywang.wx.miniapp.bean.shop.response.WxMaOrderShippingInfoGetResponse;
-import cn.binarywang.wx.miniapp.bean.shop.response.WxMaOrderShippingIsTradeManagedResponse;
+import cn.binarywang.wx.miniapp.bean.shop.response.*;
 import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
 import com.google.gson.JsonObject;
 import lombok.RequiredArgsConstructor;
@@ -20,7 +17,6 @@
 import me.chanjar.weixin.common.util.json.GsonParser;
 
 import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.OrderShipping.*;
-import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.OTHER.GET_CATEGORY;
 
 
 /**
@@ -123,6 +119,34 @@ public WxMaOrderShippingInfoBaseResponse setMsgJumpPath(String path) throws WxEr
     return request(SET_MSG_JUMP_PATH, jsonObject, WxMaOrderShippingInfoBaseResponse.class);
   }
 
+  /**
+   * 查询小程序是否已完成交易结算管理确认
+   *
+   * @param appId 待查询小程序的 appid，非服务商调用时仅能查询本账号
+   * @return WxMaOrderShippingITMCCompletedResult
+   * @throws WxErrorException e
+   */
+  @Override
+  public WxMaOrderShippingITMCCompletedResult isTradeManagementConfirmationCompleted(String appId) throws WxErrorException {
+    JsonObject jsonObject = GsonHelper.buildJsonObject("appid", appId);
+    return request(IS_TRADE_MANAGEMENT_CONFIRMATION_COMPLETED, jsonObject, WxMaOrderShippingITMCCompletedResult.class);
+  }
+
+  /**
+   * 特殊发货报备
+   *
+   * @param orderId 需要特殊发货报备的订单号，可传入微信支付单号或商户单号
+   * @param type    特殊发货报备类型，1为预售商品订单，2为测试订单
+   * @param delayTo 预计发货时间的unix时间戳，type为1时必填，type为2可省略
+   * @return WxMaOrderShippingInfoBaseResponse
+   * @throws WxErrorException e
+   */
+  @Override
+  public WxMaOrderShippingInfoBaseResponse opSpecialOrder(String orderId, Integer type, Long delayTo) throws WxErrorException {
+    JsonObject jsonObject = GsonHelper.buildJsonObject("order_id", orderId, "type", type, "delay_to", delayTo);
+    return request(OP_SPECIAL_ORDER, jsonObject, WxMaOrderShippingInfoBaseResponse.class);
+  }
+
   private <T> T request(String url, Object request, Class<T> resultT) throws WxErrorException {
     String responseContent = this.wxMaService.post(url, request);
     JsonObject jsonObject = GsonParser.parse(responseContent);
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaProductServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaProductServiceImpl.java
index 6e6ee05e38..d3c1eb2c3f 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaProductServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaProductServiceImpl.java
@@ -4,11 +4,7 @@
 import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.OTHER.GET_CATEGORY;
 import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.OTHER.GET_FREIGHT_TEMPLATE;
 import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.OTHER.IMG_UPLOAD;
-import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.Sku.PRODUCT_ADD_SKU_URL;
-import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.Sku.PRODUCT_BATCH_ADD_SKU_URL;
-import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.Sku.PRODUCT_DEL_SKU_URL;
 import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.Sku.PRODUCT_SKU_LIST;
-import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.Order.PRODUCT_ORDER_GET_LIST;
 import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.Sku.PRODUCT_ADD_SKU_URL;
 import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.Sku.PRODUCT_BATCH_ADD_SKU_URL;
 import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.Product.Sku.PRODUCT_DEL_SKU_URL;
@@ -28,9 +24,6 @@
 import cn.binarywang.wx.miniapp.api.WxMaService;
 import cn.binarywang.wx.miniapp.bean.product.WxMinishopAddGoodsSkuData;
 import cn.binarywang.wx.miniapp.bean.product.WxMinishopAddGoodsSpuData;
-import cn.binarywang.wx.miniapp.bean.product.WxMinishopOrderListResponse;
-import cn.binarywang.wx.miniapp.bean.product.WxMinishopResult;
-import cn.binarywang.wx.miniapp.bean.product.WxMinishopSku;
 import cn.binarywang.wx.miniapp.bean.product.WxMinishopGetBrandResponse;
 import cn.binarywang.wx.miniapp.bean.product.WxMinishopGetCategoryResponse;
 import cn.binarywang.wx.miniapp.bean.product.WxMinishopGetFrightTemplateResponse;
@@ -52,11 +45,7 @@
 import java.util.List;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import me.chanjar.weixin.common.api.WxConsts;
 import me.chanjar.weixin.common.bean.result.WxMinishopImageUploadResult;
-import me.chanjar.weixin.common.enums.WxType;
-import me.chanjar.weixin.common.error.WxError;
-import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.MinishopUploadRequestExecutor;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
@@ -142,7 +131,7 @@ public WxMinishopResult<WxMinishopAddGoodsSpuData> addSpu(WxMinishopSpu spu) thr
     if (respObj.get(ERR_CODE).getAsInt() != 0) {
       throw new WxErrorException(WxError.fromJson(response, WxType.MiniApp));
     }
-    WxMinishopResult result = new WxMinishopResult();
+    WxMinishopResult<WxMinishopAddGoodsSpuData> result = new WxMinishopResult<>();
     result.setErrcode(respObj.get(ERR_CODE).getAsInt());
     JsonObject dataObj = respObj.get("data").getAsJsonObject();
     WxMinishopAddGoodsSpuData resultData = new WxMinishopAddGoodsSpuData();
@@ -200,7 +189,7 @@ public WxMinishopResult<WxMinishopAddGoodsSpuData> updateSpu(WxMinishopSpu spu)
     if (respObj.get(ERR_CODE).getAsInt() != 0) {
       throw new WxErrorException(WxError.fromJson(response, WxType.MiniApp));
     }
-    WxMinishopResult result = new WxMinishopResult();
+    WxMinishopResult<WxMinishopAddGoodsSpuData> result = new WxMinishopResult<>();
     result.setErrcode(respObj.get(ERR_CODE).getAsInt());
     JsonObject dataObj = respObj.get("data").getAsJsonObject();
     WxMinishopAddGoodsSpuData resultData = new WxMinishopAddGoodsSpuData();
@@ -259,7 +248,7 @@ public WxMinishopResult<WxMinishopAddGoodsSkuData> minishiopGoodsAddSku(
     if (jsonObject.get(ERR_CODE).getAsInt() != 0) {
       throw new WxErrorException(WxError.fromJson(response, WxType.MiniApp));
     }
-    WxMinishopResult result = new WxMinishopResult();
+    WxMinishopResult<WxMinishopAddGoodsSkuData> result = new WxMinishopResult<>();
     result.setErrcode(jsonObject.get(ERR_CODE).getAsInt());
     JsonObject dataObj = jsonObject.get("data").getAsJsonObject();
     WxMinishopAddGoodsSkuData resultData = new WxMinishopAddGoodsSkuData();
@@ -279,7 +268,7 @@ public WxMinishopResult<List<WxMinishopAddGoodsSkuData>> minishopGoodsBatchAddSk
       throw new WxErrorException(WxError.fromJson(response, WxType.MiniApp));
     }
 
-    WxMinishopResult result = new WxMinishopResult();
+    WxMinishopResult<List<WxMinishopAddGoodsSkuData>> result = new WxMinishopResult<>();
     result.setErrcode(jsonObject.get(ERR_CODE).getAsInt());
     JsonArray jsonArray = jsonObject.get("data").getAsJsonArray();
     List<WxMinishopAddGoodsSkuData> skuData = new ArrayList<>();
@@ -317,7 +306,7 @@ public WxMinishopResult<WxMinishopUpdateGoodsSkuData> minishopGoodsUpdateSku(
     if (jsonObject.get(ERR_CODE).getAsInt() != 0) {
       throw new WxErrorException(WxError.fromJson(response, WxType.MiniApp));
     }
-    WxMinishopResult result = new WxMinishopResult();
+    WxMinishopResult<WxMinishopUpdateGoodsSkuData> result = new WxMinishopResult<>();
     result.setErrcode(jsonObject.get(ERR_CODE).getAsInt());
     JsonObject dataObj = jsonObject.get("data").getAsJsonObject();
     WxMinishopUpdateGoodsSkuData resultData = new WxMinishopUpdateGoodsSkuData();
@@ -339,7 +328,7 @@ public WxMinishopResult<WxMinishopUpdateGoodsSkuData> minishopGoodsUpdateSkuPric
       throw new WxErrorException(WxError.fromJson(response, WxType.MiniApp));
     }
 
-    WxMinishopResult result = new WxMinishopResult();
+    WxMinishopResult<WxMinishopUpdateGoodsSkuData> result = new WxMinishopResult<>();
     result.setErrcode(jsonObject.get(ERR_CODE).getAsInt());
     JsonObject dataObj = jsonObject.get("data").getAsJsonObject();
     WxMinishopUpdateGoodsSkuData resultData = new WxMinishopUpdateGoodsSkuData();
@@ -361,7 +350,7 @@ public WxMinishopResult<WxMinishopUpdateGoodsSkuData> minishopGoodsUpdateSkuStoc
       throw new WxErrorException(WxError.fromJson(response, WxType.MiniApp));
     }
 
-    WxMinishopResult result = new WxMinishopResult();
+    WxMinishopResult<WxMinishopUpdateGoodsSkuData> result = new WxMinishopResult<>();
     result.setErrcode(jsonObject.get(ERR_CODE).getAsInt());
     JsonObject dataObj = jsonObject.get("data").getAsJsonObject();
     WxMinishopUpdateGoodsSkuData resultData = new WxMinishopUpdateGoodsSkuData();
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceHttpClientImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceHttpClientImpl.java
index 7b1ea3e96b..9734e25933 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceHttpClientImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceHttpClientImpl.java
@@ -4,18 +4,17 @@
 import cn.binarywang.wx.miniapp.bean.WxMaStableAccessTokenRequest;
 import cn.binarywang.wx.miniapp.config.WxMaConfig;
 import lombok.extern.slf4j.Slf4j;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
+import me.chanjar.weixin.common.util.http.apache.ApacheBasicResponseHandler;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
 import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.ContentType;
 import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.BasicResponseHandler;
 import org.apache.http.impl.client.CloseableHttpClient;
 
 import java.io.IOException;
@@ -59,8 +58,8 @@ public HttpHost getRequestHttpProxy() {
   }
 
   @Override
-  public HttpType getRequestType() {
-    return HttpType.APACHE_HTTP;
+  public HttpClientType getRequestType() {
+    return HttpClientType.APACHE_HTTP;
   }
 
   @Override
@@ -74,27 +73,12 @@ protected String doGetAccessTokenRequest() throws IOException {
 
     url = String.format(url, this.getWxMaConfig().getAppid(), this.getWxMaConfig().getSecret());
 
-    HttpGet httpGet = null;
-    CloseableHttpResponse response = null;
-    try {
-      httpGet = new HttpGet(url);
-      if (this.getRequestHttpProxy() != null) {
-        RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
-        httpGet.setConfig(config);
-      }
-      response = getRequestHttpClient().execute(httpGet);
-      return new BasicResponseHandler().handleResponse(response);
-    } finally {
-      if (httpGet != null) {
-        httpGet.releaseConnection();
-      }
-      if (response != null) {
-        try {
-          response.close();
-        } catch (IOException e) {
-        }
-      }
+    HttpGet httpGet = new HttpGet(url);
+    if (this.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
+      httpGet.setConfig(config);
     }
+    return getRequestHttpClient().execute(httpGet, ApacheBasicResponseHandler.INSTANCE);
   }
 
   @Override
@@ -104,33 +88,18 @@ protected String doGetStableAccessTokenRequest(boolean forceRefresh) throws IOEx
       GET_STABLE_ACCESS_TOKEN.replace("https://api.weixin.qq.com", this.getWxMaConfig().getApiHostUrl()) :
       GET_STABLE_ACCESS_TOKEN;
 
-    HttpPost httpPost = null;
-    CloseableHttpResponse response = null;
-    try {
-      httpPost = new HttpPost(url);
-      if (this.getRequestHttpProxy() != null) {
-        RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
-        httpPost.setConfig(config);
-      }
-      WxMaStableAccessTokenRequest wxMaAccessTokenRequest = new WxMaStableAccessTokenRequest();
-      wxMaAccessTokenRequest.setAppid(this.getWxMaConfig().getAppid());
-      wxMaAccessTokenRequest.setSecret(this.getWxMaConfig().getSecret());
-      wxMaAccessTokenRequest.setGrantType("client_credential");
-      wxMaAccessTokenRequest.setForceRefresh(forceRefresh);
-      httpPost.setEntity(new StringEntity(wxMaAccessTokenRequest.toJson(), ContentType.APPLICATION_JSON));
-      response = getRequestHttpClient().execute(httpPost);
-      return new BasicResponseHandler().handleResponse(response);
-    } finally {
-      if (httpPost != null) {
-        httpPost.releaseConnection();
-      }
-      if (response != null) {
-        try {
-          response.close();
-        } catch (IOException e) {
-        }
-      }
+    HttpPost httpPost = new HttpPost(url);
+    if (this.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
     }
+    WxMaStableAccessTokenRequest wxMaAccessTokenRequest = new WxMaStableAccessTokenRequest();
+    wxMaAccessTokenRequest.setAppid(this.getWxMaConfig().getAppid());
+    wxMaAccessTokenRequest.setSecret(this.getWxMaConfig().getSecret());
+    wxMaAccessTokenRequest.setGrantType("client_credential");
+    wxMaAccessTokenRequest.setForceRefresh(forceRefresh);
+    httpPost.setEntity(new StringEntity(wxMaAccessTokenRequest.toJson(), ContentType.APPLICATION_JSON));
+    return getRequestHttpClient().execute(httpPost, ApacheBasicResponseHandler.INSTANCE);
   }
 
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceJoddHttpImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceJoddHttpImpl.java
index d2037a0732..d23d865cf9 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceJoddHttpImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceJoddHttpImpl.java
@@ -8,7 +8,7 @@
 import jodd.http.ProxyInfo;
 import jodd.http.net.SocketHttpConnectionProvider;
 import jodd.net.MimeTypes;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
 import org.apache.commons.lang3.StringUtils;
 
 import java.io.IOException;
@@ -43,8 +43,8 @@ public ProxyInfo getRequestHttpProxy() {
   }
 
   @Override
-  public HttpType getRequestType() {
-    return HttpType.JODD_HTTP;
+  public HttpClientType getRequestType() {
+    return HttpClientType.JODD_HTTP;
   }
 
   @Override
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceOkHttpImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceOkHttpImpl.java
index ff78a6984a..1053b809e9 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceOkHttpImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaServiceOkHttpImpl.java
@@ -3,7 +3,7 @@
 import cn.binarywang.wx.miniapp.api.WxMaService;
 import cn.binarywang.wx.miniapp.bean.WxMaStableAccessTokenRequest;
 import cn.binarywang.wx.miniapp.config.WxMaConfig;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
 import me.chanjar.weixin.common.util.http.okhttp.DefaultOkHttpClientBuilder;
 import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
 import okhttp3.*;
@@ -58,8 +58,8 @@ public OkHttpProxyInfo getRequestHttpProxy() {
   }
 
   @Override
-  public HttpType getRequestType() {
-    return HttpType.OK_HTTP;
+  public HttpClientType getRequestType() {
+    return HttpClientType.OK_HTTP;
   }
 
   @Override
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaSubscribeServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaSubscribeServiceImpl.java
index 2167ba062b..a7db154a68 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaSubscribeServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaSubscribeServiceImpl.java
@@ -8,7 +8,6 @@
 import me.chanjar.weixin.common.bean.subscribemsg.PubTemplateKeyword;
 import me.chanjar.weixin.common.bean.subscribemsg.TemplateInfo;
 import me.chanjar.weixin.common.bean.subscribemsg.PubTemplateTitleListResult;
-import cn.binarywang.wx.miniapp.constant.WxMaConstants;
 import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
 import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableMap;
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaXPayServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaXPayServiceImpl.java
index 5e33d1059f..29a7c51a2c 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaXPayServiceImpl.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaXPayServiceImpl.java
@@ -1,10 +1,10 @@
 package cn.binarywang.wx.miniapp.api.impl;
 
 import cn.binarywang.wx.miniapp.api.WxMaService;
-import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
-import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
 import cn.binarywang.wx.miniapp.api.WxMaXPayService;
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
 import cn.binarywang.wx.miniapp.bean.xpay.*;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.enums.WxType;
@@ -235,4 +235,217 @@ public WxMaXPayQueryPublishGoodsResponse queryPublishGoods(WxMaXPayQueryPublishG
 
     return getDetailResponse;
   }
+
+  @Override
+  public WxMaXPayQueryBizBalanceResponse queryBizBalance(WxMaXPayQueryBizBalanceRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+    final String postBody = request.toJson();
+    final String uri = sigParams.signUriWithPay(QUERY_BIZ_BALANCE_URL, postBody);
+    String responseContent = this.service.post(uri, postBody);
+    WxMaXPayQueryBizBalanceResponse getDetailResponse = WxMaGsonBuilder.create()
+      .fromJson(responseContent, WxMaXPayQueryBizBalanceResponse.class);
+
+    if (getDetailResponse.getErrcode() != 0) {
+      throw new WxErrorException(
+        new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+    }
+
+    return getDetailResponse;
+  }
+
+  @Override
+  public WxMaXPayQueryTransferAccountResponse queryTransferAccount(WxMaXPayQueryTransferAccountRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+    final String postBody = request.toJson();
+    final String uri = sigParams.signUriWithPay(QUERY_TRANSFER_ACCOUNT_URL, postBody);
+    String responseContent = this.service.post(uri, postBody);
+    WxMaXPayQueryTransferAccountResponse getDetailResponse = WxMaGsonBuilder.create()
+      .fromJson(responseContent, WxMaXPayQueryTransferAccountResponse.class);
+    if (getDetailResponse.getErrcode() != 0) {
+      throw new WxErrorException(
+        new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+    }
+    return getDetailResponse;
+  }
+
+  @Override
+  public WxMaXPayQueryAdverFundsResponse queryAdverFunds(WxMaXPayQueryAdverFundsRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+    final String postBody = request.toJson();
+    final String uri = sigParams.signUriWithPay(QUERY_ADVER_FUNDS_URL, postBody);
+    String responseContent = this.service.post(uri, postBody);
+    WxMaXPayQueryAdverFundsResponse getDetailResponse = WxMaGsonBuilder.create()
+      .fromJson(responseContent, WxMaXPayQueryAdverFundsResponse.class);
+    if (getDetailResponse.getErrcode() != 0) {
+      throw new WxErrorException(
+        new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+    }
+    return getDetailResponse;
+  }
+
+  @Override
+  public WxMaXPayCreateFundsBillResponse createFundsBill(WxMaXPayCreateFundsBillRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+    final String postBody = request.toJson();
+    final String uri = sigParams.signUriWithPay(CREATE_FUNDS_BILL_URL, postBody);
+    String responseContent = this.service.post(uri, postBody);
+    WxMaXPayCreateFundsBillResponse getDetailResponse = WxMaGsonBuilder.create()
+      .fromJson(responseContent, WxMaXPayCreateFundsBillResponse.class);
+    if (getDetailResponse.getErrcode() != 0) {
+      throw new WxErrorException(
+        new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+    }
+    return getDetailResponse;
+  }
+
+  @Override
+  public WxMaBaseResponse bindTransferAccount(WxMaXPayBindTransferAccountRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+    final String postBody = request.toJson();
+    final String uri = sigParams.signUriWithPay(BIND_TRANSFER_ACCOUNT_URL, postBody);
+    String responseContent = this.service.post(uri, postBody);
+    WxMaBaseResponse getDetailResponse = WxMaGsonBuilder.create()
+      .fromJson(responseContent, WxMaBaseResponse.class);
+    if (getDetailResponse.getErrcode() != 0) {
+      throw new WxErrorException(
+        new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+    }
+    return getDetailResponse;
+  }
+
+  @Override
+  public WxMaXPayQueryFundsBillResponse queryFundsBill(WxMaXPayQueryFundsBillRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+    final String postBody = request.toJson();
+    final String uri = sigParams.signUriWithPay(QUERY_FUNDS_BILL_URL, postBody);
+    String responseContent = this.service.post(uri, postBody);
+    WxMaXPayQueryFundsBillResponse getDetailResponse = WxMaGsonBuilder.create()
+      .fromJson(responseContent, WxMaXPayQueryFundsBillResponse.class);
+    if (getDetailResponse.getErrcode() != 0) {
+      throw new WxErrorException(
+        new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+    }
+    return getDetailResponse;
+  }
+
+  @Override
+  public WxMaXPayQueryRecoverBillResponse queryRecoverBill(WxMaXPayQueryRecoverBillRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+    final String postBody = request.toJson();
+    final String uri = sigParams.signUriWithPay(QUERY_RECOVER_BILL_URL, postBody);
+    String responseContent = this.service.post(uri, postBody);
+    WxMaXPayQueryRecoverBillResponse getDetailResponse = WxMaGsonBuilder.create()
+      .fromJson(responseContent, WxMaXPayQueryRecoverBillResponse.class);
+    if (getDetailResponse.getErrcode() != 0) {
+      throw new WxErrorException(
+        new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+    }
+    return getDetailResponse;
+  }
+
+
+  @Override
+  public WxMaXPayGetComplaintListResponse getComplaintList(WxMaXPayGetComplaintListRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+    final String postBody = request.toJson();
+    final String uri = sigParams.signUriWithPay(GET_COMPLAINT_LIST_URL, postBody);
+    String responseContent = this.service.post(uri, postBody);
+    WxMaXPayGetComplaintListResponse getDetailResponse = WxMaGsonBuilder.create()
+      .fromJson(responseContent, WxMaXPayGetComplaintListResponse.class);
+    if (getDetailResponse.getErrcode() != 0) {
+      throw new WxErrorException(
+        new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+    }
+    return getDetailResponse;
+  }
+
+  @Override
+  public WxMaXPayGetComplaintDetailResponse getComplaintDetail(WxMaXPayGetComplaintDetailRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+    final String postBody = request.toJson();
+    final String uri = sigParams.signUriWithPay(GET_COMPLAINT_DETAIL_URL, postBody);
+    String responseContent = this.service.post(uri, postBody);
+    WxMaXPayGetComplaintDetailResponse getDetailResponse = WxMaGsonBuilder.create()
+      .fromJson(responseContent, WxMaXPayGetComplaintDetailResponse.class);
+    if (getDetailResponse.getErrcode() != 0) {
+      throw new WxErrorException(
+        new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+    }
+    return getDetailResponse;
+  }
+
+  @Override
+  public WxMaXPayGetNegotiationHistoryResponse getNegotiationHistory(WxMaXPayGetNegotiationHistoryRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+    final String postBody = request.toJson();
+    final String uri = sigParams.signUriWithPay(GET_NEGOTIATION_HISTORY_URL, postBody);
+    String responseContent = this.service.post(uri, postBody);
+    WxMaXPayGetNegotiationHistoryResponse getDetailResponse = WxMaGsonBuilder.create()
+      .fromJson(responseContent, WxMaXPayGetNegotiationHistoryResponse.class);
+    if (getDetailResponse.getErrcode() != 0) {
+      throw new WxErrorException(
+        new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+    }
+    return getDetailResponse;
+  }
+
+  @Override
+  public WxMaBaseResponse responseComplaint(WxMaXPayResponseComplaintRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+    final String postBody = request.toJson();
+    final String uri = sigParams.signUriWithPay(RESPONSE_COMPLAINT_URL, postBody);
+    String responseContent = this.service.post(uri, postBody);
+    WxMaBaseResponse getDetailResponse = WxMaGsonBuilder.create()
+      .fromJson(responseContent, WxMaBaseResponse.class);
+    if (getDetailResponse.getErrcode() != 0) {
+      throw new WxErrorException(
+        new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+    }
+    return getDetailResponse;
+  }
+
+  @Override
+  public WxMaBaseResponse completeComplaint(WxMaXPayCompleteComplaintRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+    final String postBody = request.toJson();
+    final String uri = sigParams.signUriWithPay(COMPLETE_COMPLAINT_URL, postBody);
+    String responseContent = this.service.post(uri, postBody);
+    WxMaBaseResponse getDetailResponse = WxMaGsonBuilder.create()
+      .fromJson(responseContent, WxMaBaseResponse.class);
+    if (getDetailResponse.getErrcode() != 0) {
+      throw new WxErrorException(
+        new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+    }
+    return getDetailResponse;
+  }
+
+  @Override
+  public WxMaXPayUploadVpFileResponse uploadVpFile(WxMaXPayUploadVpFileRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+    final String postBody = request.toJson();
+    final String uri = sigParams.signUriWithPay(UPLOAD_VP_FILE_URL, postBody);
+    String responseContent = this.service.post(uri, postBody);
+    WxMaXPayUploadVpFileResponse getDetailResponse = WxMaGsonBuilder.create()
+      .fromJson(responseContent, WxMaXPayUploadVpFileResponse.class);
+    if (getDetailResponse.getErrcode() != 0) {
+      throw new WxErrorException(
+        new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+    }
+    return getDetailResponse;
+  }
+
+  @Override
+  public WxMaXPayGetUploadFileSignResponse getUploadFileSign(WxMaXPayGetUploadFileSignRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+    final String postBody = request.toJson();
+    final String uri = sigParams.signUriWithPay(GET_UPLOAD_FILE_SIGN_URL, postBody);
+    String responseContent = this.service.post(uri, postBody);
+    WxMaXPayGetUploadFileSignResponse getDetailResponse = WxMaGsonBuilder.create()
+      .fromJson(responseContent, WxMaXPayGetUploadFileSignResponse.class);
+    if (getDetailResponse.getErrcode() != 0) {
+      throw new WxErrorException(
+        new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+    }
+    return getDetailResponse;
+  }
+
+  @Override
+  public WxMaXPayDownloadAdverfundsOrderResponse downloadAdverfundsOrder(WxMaXPayDownloadAdverfundsOrderRequest request, WxMaXPaySigParams sigParams) throws WxErrorException {
+    final String postBody = request.toJson();
+    final String uri = sigParams.signUriWithPay(DOWNLOAD_ADVERFUNDS_ORDER_URL, postBody);
+    String responseContent = this.service.post(uri, postBody);
+    WxMaXPayDownloadAdverfundsOrderResponse getDetailResponse = WxMaGsonBuilder.create()
+      .fromJson(responseContent, WxMaXPayDownloadAdverfundsOrderResponse.class);
+    if (getDetailResponse.getErrcode() != 0) {
+      throw new WxErrorException(
+        new WxError(getDetailResponse.getErrcode(), getDetailResponse.getErrmsg()));
+    }
+    return getDetailResponse;
+  }
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java
index 7a004b845c..d95882a240 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/WxMaMessage.java
@@ -31,7 +31,7 @@ public class WxMaMessage implements Serializable {
   private static final long serialVersionUID = -3586245291677274914L;
 
   /**
-   * 使用dom4j解析的存放所有xml属性和值的map.
+   * 使用dom4j解析的存放所有xml或json属性和值的map.
    */
   private Map<String, Object> allFieldsMap;
 
@@ -212,6 +212,51 @@ public class WxMaMessage implements Serializable {
   @XStreamAlias("SubscribeMsgSentEvent")
   private WxMaSubscribeMsgEvent.SubscribeMsgSentEvent subscribeMsgSentEvent;
 
+  // 小程序基本信息
+
+  //region 小程序基本信息 infoType=notify_3rd_wxa_auth_and_icp
+
+  /**
+   * 返回值
+   */
+  @XStreamAlias("ret")
+  private String ret;
+
+  /**
+   * 一级类目id
+   */
+  @XStreamAlias("first")
+  private String first;
+
+  /**
+   * 二级类目id
+   */
+  @XStreamAlias("second")
+  private String second;
+
+  /**
+   * 驳回原因
+   */
+  @XStreamAlias("reason")
+  private String reason;
+
+  /**
+   * 小程序代码审核驳回原因
+   */
+  @XStreamAlias("Reason")
+  private String weAppReason;
+
+  /**
+   * 昵称
+   */
+  @XStreamAlias("nickname")
+  private String nickname;
+
+  /**
+   * 原始通知内容
+   */
+  private String context;
+
   /**
    * 不要直接使用这个字段，
    * 这个字段只是为了适配 SubscribeMsgPopupEvent SubscribeMsgChangeEvent SubscribeMsgSentEvent
@@ -261,7 +306,9 @@ public static WxMaMessage fromEncryptedXml(String encryptedXml,
                                              WxMaConfig wxMaConfig, String timestamp, String nonce,
                                              String msgSignature) {
     String plainText = new WxMaCryptUtils(wxMaConfig).decryptXml(msgSignature, timestamp, nonce, encryptedXml);
-    return fromXml(plainText);
+    WxMaMessage wxMaMessage = fromXml(plainText);
+    wxMaMessage.setContext(plainText);
+    return wxMaMessage;
   }
 
   public static WxMaMessage fromEncryptedXml(InputStream is, WxMaConfig wxMaConfig, String timestamp,
@@ -287,6 +334,7 @@ public static WxMaMessage fromJson(String json) {
       }
       message.setUselessMsg(null);
     }
+    message.setAllFieldsMap(WxMaGsonBuilder.create().fromJson(json, Map.class));
     return message;
   }
 
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/express/result/WxMaExpressOrderInfoResult.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/express/result/WxMaExpressOrderInfoResult.java
index 275c2d093b..b3225d810d 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/express/result/WxMaExpressOrderInfoResult.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/express/result/WxMaExpressOrderInfoResult.java
@@ -51,6 +51,11 @@ public class WxMaExpressOrderInfoResult extends WxMaExpressInfoResult implements
   @SerializedName("waybill_data")
   private List<Map<String,String>> waybillData;
 
+  /**
+   * 运单状态, 0正常，1取消
+   */
+  @SerializedName("order_status")
+  private Integer orderStatus;
 
   public static WxMaExpressOrderInfoResult fromJson(String json) {
     return WxMaGsonBuilder.create().fromJson(json, WxMaExpressOrderInfoResult.class);
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/BasicWxMaOrder.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/BasicWxMaOrder.java
index 868cf5e5c3..e0bbeccf2f 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/BasicWxMaOrder.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/BasicWxMaOrder.java
@@ -1,16 +1,19 @@
 package cn.binarywang.wx.miniapp.bean.intractiy;
 
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 
+@Slf4j
 class BasicWxMaOrder {
-
   private String wxStoreId;
   private String userName;
   private String userPhone;
   private double userLng;
   private double userLat;
   private String userAddress;
-  private int useSandbox;
+
+  /** 如果不用沙盒测试环境，传NULL（不是0），用沙盒传1 */
+  private Integer useSandbox;
 
   public String getWxStoreId() {
     return wxStoreId;
@@ -60,11 +63,16 @@ public void setUserAddress(String userAddress) {
     this.userAddress = userAddress;
   }
 
-  public int isUseSandbox() {
+  public Integer getUseSandbox() {
     return useSandbox;
   }
 
-  public void setUseSandbox(int useSandbox) {
+  public void setUseSandbox(Integer useSandbox) {
+    if (useSandbox != null && useSandbox != 1) {
+      log.warn(
+          "目前(2024.11)useSandbox只有2个合法值：" + " 1:使用沙盒环境； null：不使用沙盒环境。建议查询微信文档确认下值「{}」是否合法。",
+          useSandbox);
+    }
     this.useSandbox = useSandbox;
   }
 
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaOrder.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaOrder.java
index fbec5c8c6c..0a752d9f9f 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaOrder.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaOrder.java
@@ -11,6 +11,7 @@ public class WxMaOrder extends WxMaAddOrderRequest {
   private String deliveryNo;
   private int actualfee;
   private int deductfee;
+  private int distance;
   private long createTime;
   private long acceptTime;
   private long fetchTime;
@@ -196,6 +197,14 @@ public Date getCancelDate() {
     return cancelTime == 0 ? null : new Date(cancelTime * 1000);
   }
 
+  public int getDistance() {
+    return distance;
+  }
+
+  public void setDistance(int distance) {
+    this.distance = distance;
+  }
+
   @Override
   public String toString() {
     return ToStringBuilder.reflectionToString(this);
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaPreAddOrderResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaPreAddOrderResponse.java
new file mode 100644
index 0000000000..f198c81baa
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/intractiy/WxMaPreAddOrderResponse.java
@@ -0,0 +1,63 @@
+package cn.binarywang.wx.miniapp.bean.intractiy;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WxMaPreAddOrderResponse {
+  private static final Logger logger = LoggerFactory.getLogger(WxMaPreAddOrderResponse.class);
+
+  /** 运力公司ID */
+  private String serviceTransId;
+
+  /** 配送距离 */
+  private int distance;
+
+  /** 预估配送费 */
+  private int estFee;
+
+  /** 商品预计送达时间 */
+  private long expectedFinishedTime;
+
+  /** 配送时长（单位：分钟） */
+  private int promiseDeliveryTime;
+
+  public String getServiceTransId() {
+    return serviceTransId;
+  }
+
+  public void setServiceTransId(String serviceTransId) {
+    this.serviceTransId = serviceTransId;
+  }
+
+  public int getDistance() {
+    return distance;
+  }
+
+  public void setDistance(int distance) {
+    this.distance = distance;
+  }
+
+  public int getEstFee() {
+    return estFee;
+  }
+
+  public void setEstFee(int estFee) {
+    this.estFee = estFee;
+  }
+
+  public long getExpectedFinishedTime() {
+    return expectedFinishedTime;
+  }
+
+  public void setExpectedFinishedTime(long expectedFinishedTime) {
+    this.expectedFinishedTime = expectedFinishedTime;
+  }
+
+  public int getPromiseDeliveryTime() {
+    return promiseDeliveryTime;
+  }
+
+  public void setPromiseDeliveryTime(int promiseDeliveryTime) {
+    this.promiseDeliveryTime = promiseDeliveryTime;
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/order/WxMaOrderManagementGetOrderDetailPath.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/order/WxMaOrderManagementGetOrderDetailPath.java
new file mode 100644
index 0000000000..b301e356e8
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/order/WxMaOrderManagementGetOrderDetailPath.java
@@ -0,0 +1,22 @@
+package cn.binarywang.wx.miniapp.bean.order;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * @author xzh
+ * @Description
+ * @createTime 2025/01/16 15:27
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class WxMaOrderManagementGetOrderDetailPath extends WxMaOrderManagementResult {
+  private static final long serialVersionUID = -5288666524298706169L;
+
+  /**
+   * 订单详情路径
+   */
+  @SerializedName("path")
+  private String path;
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/order/WxMaOrderManagementResult.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/order/WxMaOrderManagementResult.java
new file mode 100644
index 0000000000..5a903b8980
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/order/WxMaOrderManagementResult.java
@@ -0,0 +1,27 @@
+package cn.binarywang.wx.miniapp.bean.order;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author xzh
+ * @Description
+ * @createTime 2025/01/16 15:27
+ */
+@Data
+public class WxMaOrderManagementResult implements Serializable {
+  private static final long serialVersionUID = 1468925151935770503L;
+  /**
+   * 错误码
+   */
+  @SerializedName("errcode")
+  private Integer errCode;
+
+  /**
+   * 错误原因
+   */
+  @SerializedName("errmsg")
+  private String errMsg;
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaOrderShippingIsTradeManagedRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaOrderShippingIsTradeManagedRequest.java
index d70e04327a..72d1381cf2 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaOrderShippingIsTradeManagedRequest.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaOrderShippingIsTradeManagedRequest.java
@@ -7,7 +7,6 @@
 import lombok.NoArgsConstructor;
 
 import java.io.Serializable;
-import java.util.List;
 
 /**
  * @author xzh
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleAddRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleAddRequest.java
index ca3c451601..a8bd30e19a 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleAddRequest.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleAddRequest.java
@@ -7,7 +7,6 @@
 import lombok.NoArgsConstructor;
 
 import java.io.Serializable;
-import java.util.List;
 
 /**
  * @author liming1019
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleListRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleListRequest.java
index 19db2d2a1b..59aa5c3369 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleListRequest.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleListRequest.java
@@ -2,7 +2,7 @@
 
 import com.google.gson.annotations.SerializedName;
 import java.io.Serializable;
-import java.util.List;
+
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleUpdateRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleUpdateRequest.java
index ac586fa7b7..a86804bb56 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleUpdateRequest.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/WxMaShopAfterSaleUpdateRequest.java
@@ -1,6 +1,5 @@
 package cn.binarywang.wx.miniapp.bean.shop.request;
 
-import cn.binarywang.wx.miniapp.bean.shop.request.WxMaShopAfterSaleAddRequest.UploadMediaList;
 import com.google.gson.annotations.SerializedName;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/shipping/WxMaOrderCombinedShippingInfoUploadRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/shipping/WxMaOrderCombinedShippingInfoUploadRequest.java
index 74c4a76780..4d8caf010c 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/shipping/WxMaOrderCombinedShippingInfoUploadRequest.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/request/shipping/WxMaOrderCombinedShippingInfoUploadRequest.java
@@ -1,6 +1,5 @@
 package cn.binarywang.wx.miniapp.bean.shop.request.shipping;
 
-import cn.binarywang.wx.miniapp.bean.shop.request.shipping.ContactBean;
 import cn.binarywang.wx.miniapp.bean.shop.request.shipping.OrderKeyBean;
 import cn.binarywang.wx.miniapp.bean.shop.request.shipping.PayerBean;
 import com.google.gson.annotations.SerializedName;
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/response/WxMaOrderShippingITMCCompletedResult.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/response/WxMaOrderShippingITMCCompletedResult.java
new file mode 100644
index 0000000000..e2f352a543
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/response/WxMaOrderShippingITMCCompletedResult.java
@@ -0,0 +1,34 @@
+package cn.binarywang.wx.miniapp.bean.shop.response;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author xzh
+ * @Description 小程序是否已完成交易结算管理确认结果
+ * @createTime 2024/12/21 15:01
+ */
+@Data
+public class WxMaOrderShippingITMCCompletedResult implements Serializable {
+
+  private static final long serialVersionUID = -5397007157487018762L;
+  /**
+   * 错误码
+   */
+  @SerializedName("errcode")
+  private Integer errCode;
+
+  /**
+   * 错误原因
+   */
+  @SerializedName("errmsg")
+  private String errMsg;
+
+  /**
+   * 是否已完成交易结算管理确认
+   */
+  @SerializedName("completed")
+  private Boolean completed;
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/response/WxMaShopBaseResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/response/WxMaShopBaseResponse.java
index e4a015e9ab..d83c657732 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/response/WxMaShopBaseResponse.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/shop/response/WxMaShopBaseResponse.java
@@ -2,7 +2,6 @@
 
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import lombok.EqualsAndHashCode;
 
 import java.io.Serializable;
 
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/vod/WxMaVodListMediaRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/vod/WxMaVodListMediaRequest.java
index ace2c3b749..bb498d4add 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/vod/WxMaVodListMediaRequest.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/vod/WxMaVodListMediaRequest.java
@@ -16,18 +16,66 @@
 public class WxMaVodListMediaRequest implements Serializable {
   private static final long serialVersionUID = 7495157056049312108L;
 
+  /**
+   * <pre>
+   *   必填：否
+   *   说明：根据剧目id获取剧集信息
+   * </pre>
+   */
   @SerializedName("drama_id")
   private Integer dramaId;
+
+  /**
+   * <pre>
+   *   必填：否
+   *   说明：媒资文件名，支持精确匹配、模糊匹配。文件太多时使用该参数进行模糊匹配可能无法得到结果，推荐使用 media_name_fuzzy 参数。
+   * </pre>
+   */
   @SerializedName("media_name")
   private String mediaName;
 
+  /**
+   * <pre>
+   *   必填：否
+   *   说明：媒资文件名，模糊匹配。
+   * </pre>
+   */
+  @SerializedName("media_name_fuzzy")
+  private String mediaNameFuzzy;
+
+  /**
+   * <pre>
+   *   必填：否
+   *   说明：媒资上传时间 >= start_time。
+   * </pre>
+   */
   @SerializedName("start_time")
   private Long startTime;
+
+  /**
+   * <pre>
+   *   必填：否
+   *   说明：媒资上传时间 < end_time。
+   * </pre>
+   */
   @SerializedName("end_time")
   private Long endTime;
 
+  /**
+   * <pre>
+   * 必填：否
+   * 说明：分页拉取的起始偏移量。默认值：0。
+   * </pre>
+   */
   @SerializedName("offset")
   private Integer offset;
+
+  /**
+   * <pre>
+   *   必填：否
+   *   说明：分页拉取的最大返回结果数。默认值：100；最大值：100。
+   * </pre>
+   */
   @SerializedName("limit")
   private Integer limit;
 
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayBindTransferAccountRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayBindTransferAccountRequest.java
new file mode 100644
index 0000000000..dcabbe8e94
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayBindTransferAccountRequest.java
@@ -0,0 +1,32 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayBindTransferAccountRequest implements Serializable {
+  private static final long serialVersionUID = 7495157056049312108L;
+  @SerializedName("transfer_account_uid")
+  private Long transferAccountUid;
+  @SerializedName("transfer_account_org_name")
+  private String transferAccountOrgName;
+  @SerializedName("env")
+  private Integer env;
+
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayCompleteComplaintRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayCompleteComplaintRequest.java
new file mode 100644
index 0000000000..2753a9eea9
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayCompleteComplaintRequest.java
@@ -0,0 +1,30 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayCompleteComplaintRequest implements Serializable {
+  private static final long serialVersionUID = 7495157056049312108L;
+  @SerializedName("env")
+  private Integer env;
+  @SerializedName("complaint_id")
+  private String complaintId;
+
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayCreateFundsBillRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayCreateFundsBillRequest.java
new file mode 100644
index 0000000000..1e6fb4fc71
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayCreateFundsBillRequest.java
@@ -0,0 +1,48 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayCreateFundsBillRequest implements Serializable {
+  private static final long serialVersionUID = 7495157056049312108L;
+  @SerializedName("transfer_amount")
+  private Integer transferAmount;
+  @SerializedName("transfer_account_uid")
+  private Long transferAccountUid;
+  @SerializedName("transfer_account_name")
+  private String transferAccountName;
+  @SerializedName("transfer_account_agency_id")
+  private Integer transferAccountAgencyId;
+  @SerializedName("request_id")
+  private String requestId;
+  @SerializedName("settle_begin")
+  private Long settleBegin;
+  @SerializedName("settle_end")
+  private Long settleEnd;
+  @SerializedName("env")
+  private Integer env;
+  @SerializedName("authorize_advertise")
+  private Integer authorizeAdvertise;
+  @SerializedName("fund_type")
+  private Integer fundType;
+
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
+
+
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayCreateFundsBillResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayCreateFundsBillResponse.java
new file mode 100644
index 0000000000..745976d017
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayCreateFundsBillResponse.java
@@ -0,0 +1,30 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayCreateFundsBillResponse extends WxMaBaseResponse implements Serializable {
+  private static final long serialVersionUID = 7495157056049312109L;
+
+
+  @SerializedName("bill_id")
+  private String billId;
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
+
+
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayDownloadAdverfundsOrderRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayDownloadAdverfundsOrderRequest.java
new file mode 100644
index 0000000000..8ae6135860
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayDownloadAdverfundsOrderRequest.java
@@ -0,0 +1,31 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @auther fancg
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayDownloadAdverfundsOrderRequest implements Serializable {
+  private static final long serialVersionUID = 7495157056049312108L;
+  @SerializedName("fund_id")
+  private String fundId;
+  @SerializedName("env")
+  private Integer env;
+
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayDownloadAdverfundsOrderResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayDownloadAdverfundsOrderResponse.java
new file mode 100644
index 0000000000..0a64784564
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayDownloadAdverfundsOrderResponse.java
@@ -0,0 +1,27 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayDownloadAdverfundsOrderResponse extends WxMaBaseResponse implements Serializable {
+  private static final long serialVersionUID = 7495157056049312109L;
+
+  @SerializedName("url")
+  private String url;
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintDetailRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintDetailRequest.java
new file mode 100644
index 0000000000..24a2517435
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintDetailRequest.java
@@ -0,0 +1,30 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayGetComplaintDetailRequest implements Serializable {
+  private static final long serialVersionUID = 7495157056049312108L;
+  @SerializedName("env")
+  private Integer env;
+  @SerializedName("complaint_id")
+  private String complaintId;
+
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintDetailResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintDetailResponse.java
new file mode 100644
index 0000000000..497dcee0e0
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintDetailResponse.java
@@ -0,0 +1,101 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayGetComplaintDetailResponse extends WxMaBaseResponse implements Serializable {
+  private static final long serialVersionUID = 7495157056049312109L;
+
+
+  @SerializedName("complaint")
+  private Complaint complaint;
+
+  @Data
+  public static class Complaint {
+    @SerializedName("complaint_id")
+    private String complaintId;
+    @SerializedName("complaint_time")
+    private String complaintTime;
+    @SerializedName("complaint_detail")
+    private String complaintDetail;
+    @SerializedName("complaint_state")
+    private String complaintState;
+    @SerializedName("payer_phone")
+    private String payerPhone;
+    @SerializedName("payer_openid")
+    private String payerOpenid;
+    @SerializedName("complaint_order_info")
+    private List<ComplaintOrderInfo> complaintOrderInfo;
+    @SerializedName("complaint_full_refunded")
+    private Boolean complaintFullRefunded;
+    @SerializedName("incoming_user_response")
+    private Boolean incomingUserResponse;
+    @SerializedName("user_complaint_times")
+    private Integer userComplaintTimes;
+    @SerializedName("complaint_media_list")
+    private List<ComplaintMedia> complaintMediaList;
+    @SerializedName("problem_description")
+    private String problemDescription;
+    @SerializedName("problem_type")
+    private String problemType;
+    @SerializedName("apply_refund_amount")
+    private Integer applyRefundAmount;
+    @SerializedName("user_tag_list")
+    private List<String> userTagList;
+    @SerializedName("service_order_info")
+    private List<ServiceOrderInfo> serviceOrderInfo;
+
+
+  }
+
+  @Data
+  public static class ComplaintOrderInfo {
+    @SerializedName("transaction_id")
+    private String transactionId;
+    @SerializedName("out_trade_no")
+    private String outTradeNo;
+    @SerializedName("amount")
+    private Integer amount;
+    @SerializedName("wxa_out_trade_no")
+    private String wxaOutTradeNo;
+    @SerializedName("wx_order_id")
+    private String wxOrderId;
+  }
+
+  @Data
+  public static class ComplaintMedia {
+
+    @SerializedName("media_type")
+    private String mediaType;
+    @SerializedName("media_url")
+    private List<String> mediaUrl;
+  }
+
+  @Data
+  public static class ServiceOrderInfo {
+    @SerializedName("order_id")
+    private String orderId;
+    @SerializedName("out_order_no")
+    private String outOrderNo;
+    @SerializedName("state")
+    private String state;
+  }
+
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintListRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintListRequest.java
new file mode 100644
index 0000000000..69c9d0aaf5
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintListRequest.java
@@ -0,0 +1,36 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayGetComplaintListRequest implements Serializable {
+    private static final long serialVersionUID = 7495157056049312108L;
+    @SerializedName("env")
+    private Integer env;
+    @SerializedName("begin_date")
+    private String beginDate;
+    @SerializedName("end_date")
+    private String endDate;
+    @SerializedName("offset")
+    private Integer offset;
+    @SerializedName("limit")
+    private Integer limit;
+
+
+    public String toJson() {
+        return WxMaGsonBuilder.create().toJson(this);
+    }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintListResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintListResponse.java
new file mode 100644
index 0000000000..a1d926cf8f
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetComplaintListResponse.java
@@ -0,0 +1,102 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayGetComplaintListResponse extends WxMaBaseResponse implements Serializable {
+    private static final long serialVersionUID = 7495157056049312109L;
+
+
+    @SerializedName("total")
+    private Integer total;
+    @SerializedName("complaints")
+    private List<Complaint> complaints;
+
+    @Data
+    public static class Complaint {
+        @SerializedName("complaint_id")
+        private String complaintId;
+        @SerializedName("complaint_time")
+        private String complaintTime;
+        @SerializedName("complaint_detail")
+        private String complaintDetail;
+        @SerializedName("complaint_state")
+        private String complaintState;
+        @SerializedName("payer_phone")
+        private String payerPhone;
+        @SerializedName("payer_openid")
+        private String payerOpenid;
+        @SerializedName("complaint_order_info")
+        private List<ComplaintOrderInfo> complaintOrderInfo;
+        @SerializedName("complaint_full_refunded")
+        private Boolean complaintFullRefunded;
+        @SerializedName("incoming_user_response")
+        private Boolean incomingUserResponse;
+        @SerializedName("user_complaint_times")
+        private Integer userComplaintTimes;
+        @SerializedName("complaint_media_list")
+        private List<ComplaintMedia> complaintMediaList;
+        @SerializedName("problem_description")
+        private String problemDescription;
+        @SerializedName("problem_type")
+        private String problemType;
+        @SerializedName("apply_refund_amount")
+        private Integer applyRefundAmount;
+        @SerializedName("user_tag_list")
+        private List<String> userTagList;
+        @SerializedName("service_order_info")
+        private List<ServiceOrderInfo> serviceOrderInfo;
+
+
+    }
+
+    @Data
+    public static class ComplaintOrderInfo {
+        @SerializedName("transaction_id")
+        private String transactionId;
+        @SerializedName("out_trade_no")
+        private String outTradeNo;
+        @SerializedName("amount")
+        private Integer amount;
+        @SerializedName("wxa_out_trade_no")
+        private String wxaOutTradeNo;
+        @SerializedName("wx_order_id")
+        private String wxOrderId;
+    }
+
+    @Data
+    public static class ComplaintMedia {
+
+        @SerializedName("media_type")
+        private String mediaType;
+        @SerializedName("media_url")
+        private List<String> mediaUrl;
+    }
+
+    @Data
+    public static class ServiceOrderInfo {
+        @SerializedName("order_id")
+        private String orderId;
+        @SerializedName("out_order_no")
+        private String outOrderNo;
+        @SerializedName("state")
+        private String state;
+    }
+
+    public String toJson() {
+        return WxMaGsonBuilder.create().toJson(this);
+    }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetNegotiationHistoryRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetNegotiationHistoryRequest.java
new file mode 100644
index 0000000000..26dee2c9b9
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetNegotiationHistoryRequest.java
@@ -0,0 +1,34 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayGetNegotiationHistoryRequest implements Serializable {
+  private static final long serialVersionUID = 7495157056049312108L;
+  @SerializedName("env")
+  private Integer env;
+  @SerializedName("complaint_id")
+  private String complaintId;
+  @SerializedName("offset")
+  private Integer offset;
+  @SerializedName("limit")
+  private Integer limit;
+
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetNegotiationHistoryResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetNegotiationHistoryResponse.java
new file mode 100644
index 0000000000..73d8220b7a
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetNegotiationHistoryResponse.java
@@ -0,0 +1,56 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayGetNegotiationHistoryResponse extends WxMaBaseResponse implements Serializable {
+  private static final long serialVersionUID = 7495157056049312109L;
+
+
+  @SerializedName("total")
+  private Integer total;
+  @SerializedName("history")
+  private List<History> history;
+
+  @Data
+  public static class History {
+    @SerializedName("log_id")
+    private String logId;
+    @SerializedName("operator")
+    private String operator;
+    @SerializedName("operate_time")
+    private String operateTime;
+    @SerializedName("operate_type")
+    private String operateType;
+    @SerializedName("operate_details")
+    private String operateDetails;
+    @SerializedName("complaint_media_list")
+    private List<ComplaintMedia> complaintMediaList;
+
+    @Data
+    public static class ComplaintMedia {
+
+      @SerializedName("media_type")
+      private String mediaType;
+      @SerializedName("media_url")
+      private List<String> mediaUrl;
+    }
+  }
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetUploadFileSignRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetUploadFileSignRequest.java
new file mode 100644
index 0000000000..2613988842
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetUploadFileSignRequest.java
@@ -0,0 +1,34 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayGetUploadFileSignRequest implements Serializable {
+  private static final long serialVersionUID = 7495157056049312108L;
+  @SerializedName("env")
+  private Integer env;
+  @SerializedName("wxpay_url")
+  private String wxpayUrl;
+  @SerializedName("convert_cos")
+  private Boolean convertCos;
+  @SerializedName("complaint_id")
+  private String complaintId;
+
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetUploadFileSignResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetUploadFileSignResponse.java
new file mode 100644
index 0000000000..ec0cd7e3a2
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayGetUploadFileSignResponse.java
@@ -0,0 +1,30 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayGetUploadFileSignResponse extends WxMaBaseResponse implements Serializable {
+  private static final long serialVersionUID = 7495157056049312109L;
+
+
+  @SerializedName("sign")
+  private String sign;
+  @SerializedName("cos_url")
+  private String cosUrl;
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryAdverFundsRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryAdverFundsRequest.java
new file mode 100644
index 0000000000..d22d0cf40c
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryAdverFundsRequest.java
@@ -0,0 +1,44 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayQueryAdverFundsRequest implements Serializable {
+  private static final long serialVersionUID = 7495157056049312108L;
+  @SerializedName("page")
+  private Integer page;
+  @SerializedName("page_size")
+  private Integer pageSize;
+  @SerializedName("filter")
+  private Filter filter;
+  @SerializedName("env")
+  private Integer env;
+
+  @Data
+  public static class Filter {
+    @SerializedName("settle_begin")
+    private Long settleBegin;
+    @SerializedName("settle_end")
+    private Long settleEnd;
+    @SerializedName("fund_type")
+    private Integer fundType;
+
+  }
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryAdverFundsResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryAdverFundsResponse.java
new file mode 100644
index 0000000000..2095fc3a97
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryAdverFundsResponse.java
@@ -0,0 +1,49 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayQueryAdverFundsResponse extends WxMaBaseResponse implements Serializable {
+  private static final long serialVersionUID = 7495157056049312109L;
+
+  @SerializedName("adver_funds_list")
+  private List<AdverFunds> adverFundsList;
+  @SerializedName("total_page")
+  private Integer totalPage;
+
+
+  @Data
+  public static class AdverFunds {
+    @SerializedName("settle_begin")
+    private Long settleBegin;
+    @SerializedName("settle_end")
+    private Long settleEnd;
+    @SerializedName("total_amount")
+    private Integer totalAmount;
+    @SerializedName("remain_amount")
+    private Integer remainAmount;
+    @SerializedName("expire_time")
+    private Long expireTime;
+    @SerializedName("fund_type")
+    private Integer fundType;
+    @SerializedName("fund_id")
+    private String fundId;
+  }
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryBizBalanceRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryBizBalanceRequest.java
new file mode 100644
index 0000000000..767390915d
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryBizBalanceRequest.java
@@ -0,0 +1,24 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayQueryBizBalanceRequest implements Serializable {
+  private static final long serialVersionUID = 7495157056049312108L;
+  @SerializedName("env")
+  private Integer env;
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryBizBalanceResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryBizBalanceResponse.java
new file mode 100644
index 0000000000..c2f9a59db7
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryBizBalanceResponse.java
@@ -0,0 +1,36 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayQueryBizBalanceResponse extends WxMaBaseResponse implements Serializable {
+  private static final long serialVersionUID = 7495157056049312108L;
+
+  @SerializedName("balance_available")
+  private BalanceAvailable balanceAvailable;
+
+  @Data
+  public static class BalanceAvailable {
+    @SerializedName("amount")
+    private String amount;
+    @SerializedName("currency_code")
+    private String currencyCode;
+
+  }
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryFundsBillRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryFundsBillRequest.java
new file mode 100644
index 0000000000..23a4f408b6
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryFundsBillRequest.java
@@ -0,0 +1,45 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayQueryFundsBillRequest implements Serializable {
+  private static final long serialVersionUID = 7495157056049312108L;
+  @SerializedName("page")
+  private Integer page;
+  @SerializedName("page_size")
+  private Integer pageSize;
+  @SerializedName("filter")
+  private Filter filter;
+  @SerializedName("env")
+  private Integer env;
+
+  @Data
+  public static class Filter {
+    @SerializedName("oper_time_begin")
+    private Long operTimeBegin;
+    @SerializedName("oper_time_end")
+    private Long operTimeEnd;
+    @SerializedName("bill_id")
+    private String billId;
+    @SerializedName("request_id")
+    private String requestId;
+  }
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryFundsBillResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryFundsBillResponse.java
new file mode 100644
index 0000000000..e99c47171f
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryFundsBillResponse.java
@@ -0,0 +1,55 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayQueryFundsBillResponse extends WxMaBaseResponse implements Serializable {
+  private static final long serialVersionUID = 7495157056049312109L;
+
+  @SerializedName("bill_list")
+  private List<Bill> billList;
+  @SerializedName("total_page")
+  private Integer totalPage;
+
+
+  @Data
+  public static class Bill {
+    @SerializedName("bill_id")
+    private String billId;
+    @SerializedName("oper_time")
+    private Long operTime;
+    @SerializedName("settle_begin")
+    private Long settleBegin;
+    @SerializedName("settle_end")
+    private Long settleEnd;
+    @SerializedName("fund_id")
+    private String fundId;
+    @SerializedName("transfer_account_name")
+    private String transferAccountName;
+    @SerializedName("transfer_account_uid")
+    private Integer transferAccountUid;
+    @SerializedName("transfer_amount")
+    private Integer transferAmount;
+    @SerializedName("status")
+    private Integer status;
+    @SerializedName("request_id")
+    private String requestId;
+  }
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryRecoverBillRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryRecoverBillRequest.java
new file mode 100644
index 0000000000..cf76960844
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryRecoverBillRequest.java
@@ -0,0 +1,43 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayQueryRecoverBillRequest implements Serializable {
+  private static final long serialVersionUID = 7495157056049312108L;
+  @SerializedName("page")
+  private Integer page;
+  @SerializedName("page_size")
+  private Integer pageSize;
+  @SerializedName("filter")
+  private Filter filter;
+  @SerializedName("env")
+  private Integer env;
+
+  @Data
+  public static class Filter {
+    @SerializedName("recover_time_begin")
+    private Long recoverTimeBegin;
+    @SerializedName("recover_time_end")
+    private Long recoverTimeEnd;
+    @SerializedName("bill_id")
+    private String billId;
+  }
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryRecoverBillResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryRecoverBillResponse.java
new file mode 100644
index 0000000000..26c04129a3
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryRecoverBillResponse.java
@@ -0,0 +1,50 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayQueryRecoverBillResponse extends WxMaBaseResponse implements Serializable {
+  private static final long serialVersionUID = 7495157056049312109L;
+
+  @SerializedName("bill_list")
+  private List<Bill> billList;
+  @SerializedName("total_page")
+  private Integer totalPage;
+
+  @Data
+  public static class Bill {
+    @SerializedName("bill_id")
+    private String billId;
+    @SerializedName("recover_time")
+    private Long recoverTime;
+    @SerializedName("settle_begin")
+    private Long settleBegin;
+    @SerializedName("settle_end")
+    private Long settleEnd;
+    @SerializedName("fund_id")
+    private String fundId;
+    @SerializedName("recover_account_name")
+    private String recoverAccountName;
+    @SerializedName("recover_amount")
+    private Integer recoverAmount;
+    @SerializedName("refund_order_list")
+    private List<String> refundOrderList;
+  }
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryTransferAccountRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryTransferAccountRequest.java
new file mode 100644
index 0000000000..9b90dd250c
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryTransferAccountRequest.java
@@ -0,0 +1,28 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @author 秋日
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayQueryTransferAccountRequest implements Serializable {
+  private static final long serialVersionUID = 7495157056049312108L;
+  @SerializedName("env")
+  private Integer env;
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryTransferAccountResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryTransferAccountResponse.java
new file mode 100644
index 0000000000..079f088b2e
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayQueryTransferAccountResponse.java
@@ -0,0 +1,46 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayQueryTransferAccountResponse extends WxMaBaseResponse implements Serializable {
+  private static final long serialVersionUID = 7495157056049312109L;
+
+  @SerializedName("acct_list")
+  private List<AcctList> acctList;
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+
+  @Data
+  public static class AcctList {
+    @SerializedName("transfer_account_name")
+    private String transferAccountName;
+    @SerializedName("transfer_account_uid")
+    private Long transferAccountUid;
+    @SerializedName("transfer_account_agency_id")
+    private Long transferAccountAgencyId;
+    @SerializedName("transfer_account_agency_name")
+    private String transferAccountAgencyName;
+    @SerializedName("state")
+    private Integer state;
+    @SerializedName("bind_result")
+    private Integer bindResult;
+    @SerializedName("error_msg")
+    private String errorMsg;
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayResponseComplaintRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayResponseComplaintRequest.java
new file mode 100644
index 0000000000..1fac9fc9b2
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayResponseComplaintRequest.java
@@ -0,0 +1,35 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayResponseComplaintRequest implements Serializable {
+  private static final long serialVersionUID = 7495157056049312108L;
+  @SerializedName("env")
+  private Integer env;
+  @SerializedName("complaint_id")
+  private String complaintId;
+  @SerializedName("response_content")
+  private String responseContent;
+  @SerializedName("response_images")
+  private List<String> responseImages;
+
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayUploadVpFileRequest.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayUploadVpFileRequest.java
new file mode 100644
index 0000000000..2a8ac44b5b
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayUploadVpFileRequest.java
@@ -0,0 +1,34 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @date 2025-07-23
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayUploadVpFileRequest implements Serializable {
+  private static final long serialVersionUID = 7495157056049312108L;
+  @SerializedName("env")
+  private Integer env;
+  @SerializedName("base64_img")
+  private String base64Img;
+  @SerializedName("img_url")
+  private String imgUrl;
+  @SerializedName("file_name")
+  private String fileName;
+
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayUploadVpFileResponse.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayUploadVpFileResponse.java
new file mode 100644
index 0000000000..68ca557dca
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/bean/xpay/WxMaXPayUploadVpFileResponse.java
@@ -0,0 +1,28 @@
+package cn.binarywang.wx.miniapp.bean.xpay;
+
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMaXPayUploadVpFileResponse extends WxMaBaseResponse implements Serializable {
+  private static final long serialVersionUID = 7495157056049312109L;
+
+
+  @SerializedName("file_id")
+  private String fileId;
+
+  public String toJson() {
+    return WxMaGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java
index ab47d3e64d..79806dbd84 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/constant/WxMaApiUrlConstants.java
@@ -626,7 +626,7 @@ public interface InstantDelivery {
     String GET_DELIVERY_LIST_URL =
         "https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/get_delivery_list";
 
-    /** 获取运力id列表get_delivery_list 商户使用此接口获取所有运力id的列表 */
+    /** 物流服务-查询组件-更新物品信息接口 update_waybill_goods 更新物品信息 */
     String UPDATE_WAYBILL_GOODS_URL =
         "https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/update_waybill_goods";
 
@@ -751,7 +751,7 @@ public interface OrderShipping {
      * </pre>
      */
     String UPLOAD_COMBINED_SHIPPING_INFO =
-        "https://api.weixin.qq.com/wxa/sec/order/upload_combined_shipping_info";
+      "https://api.weixin.qq.com/wxa/sec/order/upload_combined_shipping_info";
 
     /**
      * 查询订单发货状态.
@@ -779,7 +779,7 @@ public interface OrderShipping {
      * </pre>
      */
     String NOTIFY_CONFIRM_RECEIVE =
-        "https://api.weixin.qq.com/wxa/sec/order/notify_confirm_receive";
+      "https://api.weixin.qq.com/wxa/sec/order/notify_confirm_receive";
 
     /**
      * 消息跳转路径设置接口.
@@ -789,6 +789,53 @@ public interface OrderShipping {
      * </pre>
      */
     String SET_MSG_JUMP_PATH = "https://api.weixin.qq.com/wxa/sec/order/set_msg_jump_path";
+
+    /**
+     * 查询小程序是否已完成交易结算管理确认.
+     *
+     * <pre>
+     * 文档地址： https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order-shipping/order-shipping.html#%E5%85%AB%E3%80%81%E6%9F%A5%E8%AF%A2%E5%B0%8F%E7%A8%8B%E5%BA%8F%E6%98%AF%E5%90%A6%E5%B7%B2%E5%AE%8C%E6%88%90%E4%BA%A4%E6%98%93%E7%BB%93%E7%AE%97%E7%AE%A1%E7%90%86%E7%A1%AE%E8%AE%A4
+     * </pre>
+     */
+    String IS_TRADE_MANAGEMENT_CONFIRMATION_COMPLETED = "https://api.weixin.qq.com/wxa/sec/order/is_trade_management_confirmation_completed";
+    /**
+     * 特殊发货报备.
+     *
+     * <pre>
+     * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order-shipping/order-shipping.html#%E5%8D%81%E3%80%81%E7%89%B9%E6%AE%8A%E5%8F%91%E8%B4%A7%E6%8A%A5%E5%A4%87
+     * </pre>
+     */
+    String OP_SPECIAL_ORDER = "https://api.weixin.qq.com/wxa/sec/order/opspecialorder";
+
+  }
+
+  /**
+   * 小程序订单管理
+   *
+   * <pre>
+   * 文档地址： https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order_center/order_center.html
+   * </pre>
+   */
+  public interface OrderManagement {
+
+    /**
+     * 配置订单详情路径.
+     *
+     * <pre>
+     * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order_center/order_center.html
+     * </pre>
+     */
+    String UPDATE_ORDER_DETAIL_PATH = "https://api.weixin.qq.com/wxa/sec/order/update_order_detail_path";
+
+    /**
+     * 查询订单详情路径.
+     *
+     * <pre>
+     * 文档地址：https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order_center/order_center.html
+     * </pre>
+     */
+    String GET_ORDER_DETAIL_PATH = "https://api.weixin.qq.com/wxa/sec/order/get_order_detail_path";
+
   }
 
   public interface Vod {
@@ -838,6 +885,22 @@ public interface XPay {
         "https://api.weixin.qq.com/xpay/start_publish_goods?pay_sig=%s";
     String QUERY_PUBLISH_GOODS_URL =
         "https://api.weixin.qq.com/xpay/query_publish_goods?pay_sig=%s";
+    String QUERY_BIZ_BALANCE_URL =
+      "https://api.weixin.qq.com/xpay/query_biz_balance?pay_sig=%s";
+    String QUERY_TRANSFER_ACCOUNT_URL = "https://api.weixin.qq.com/xpay/query_transfer_account?pay_sig=%s";
+    String QUERY_ADVER_FUNDS_URL = "https://api.weixin.qq.com/xpay/query_adver_funds?pay_sig=%s";
+    String CREATE_FUNDS_BILL_URL = "https://api.weixin.qq.com/xpay/create_funds_bill?pay_sig=%s";
+    String BIND_TRANSFER_ACCOUNT_URL = "https://api.weixin.qq.com/xpay/bind_transfer_accout?pay_sig=%s";
+    String QUERY_FUNDS_BILL_URL = "https://api.weixin.qq.com/xpay/query_funds_bill?pay_sig=%s";
+    String QUERY_RECOVER_BILL_URL = "https://api.weixin.qq.com/xpay/query_recover_bill?pay_sig=%s";
+    String GET_COMPLAINT_LIST_URL = "https://api.weixin.qq.com/xpay/get_complaint_list?pay_sig=%s";
+    String GET_COMPLAINT_DETAIL_URL = "https://api.weixin.qq.com/xpay/get_complaint_detail?pay_sig=%s";
+    String GET_NEGOTIATION_HISTORY_URL = "https://api.weixin.qq.com/xpay/get_negotiation_history?pay_sig=%s";
+    String RESPONSE_COMPLAINT_URL = "https://api.weixin.qq.com/xpay/response_complaint?pay_sig=%s";
+    String COMPLETE_COMPLAINT_URL = "https://api.weixin.qq.com/xpay/complete_complaint?pay_sig=%s";
+    String UPLOAD_VP_FILE_URL = "https://api.weixin.qq.com/xpay/upload_vp_file?pay_sig=%s";
+    String GET_UPLOAD_FILE_SIGN_URL = "https://api.weixin.qq.com/xpay/get_upload_file_sign?pay_sig=%s";
+    String DOWNLOAD_ADVERFUNDS_ORDER_URL = "https://api.weixin.qq.com/xpay/download_adverfunds_order?pay_sig=%s";
   }
 
   /**
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheApiSignaturePostRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheApiSignaturePostRequestExecutor.java
index 3dcf22b10f..0a858256a8 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheApiSignaturePostRequestExecutor.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheApiSignaturePostRequestExecutor.java
@@ -1,30 +1,27 @@
 package cn.binarywang.wx.miniapp.executor;
 
 import cn.binarywang.wx.miniapp.bean.WxMaApiResponse;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler;
-import org.apache.http.Consts;
 import org.apache.http.Header;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.impl.client.CloseableHttpClient;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
-public class ApacheApiSignaturePostRequestExecutor
-    extends ApiSignaturePostRequestExecutor<CloseableHttpClient, HttpHost> {
-  private static final Logger logger =
-      LoggerFactory.getLogger(ApacheApiSignaturePostRequestExecutor.class);
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ApacheApiSignaturePostRequestExecutor extends ApiSignaturePostRequestExecutor<CloseableHttpClient, HttpHost> {
 
-  public ApacheApiSignaturePostRequestExecutor(RequestHttp<?, ?> requestHttp) {
+  public ApacheApiSignaturePostRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
     super(requestHttp);
   }
 
@@ -49,8 +46,7 @@ public WxMaApiResponse execute(
     }
 
     if (postEntity != null) {
-      StringEntity entity = new StringEntity(postEntity, Consts.UTF_8);
-      entity.setContentType("application/json; charset=utf-8");
+      StringEntity entity = new StringEntity(postEntity, ContentType.APPLICATION_JSON.withCharset(StandardCharsets.UTF_8));
       httpPost.setEntity(entity);
     }
 
@@ -64,8 +60,6 @@ public WxMaApiResponse execute(
         }
       }
       return this.handleResponse(wxType, responseContent, respHeaders);
-    } finally {
-      httpPost.releaseConnection();
     }
   }
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheQrcodeBytesRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheQrcodeBytesRequestExecutor.java
index 58c7beabee..fff1be7fc4 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheQrcodeBytesRequestExecutor.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheQrcodeBytesRequestExecutor.java
@@ -63,8 +63,6 @@ public byte[] execute(String uri, AbstractWxMaQrcodeWrapper qrcodeWrapper, WxTyp
       }
 
       return IOUtils.toByteArray(inputStream);
-    } finally {
-      httpPost.releaseConnection();
     }
   }
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheQrcodeFileRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheQrcodeFileRequestExecutor.java
index c7f57b2f68..fbc0edcfbe 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheQrcodeFileRequestExecutor.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheQrcodeFileRequestExecutor.java
@@ -71,8 +71,6 @@ public File execute(String uri, AbstractWxMaQrcodeWrapper qrcodeWrapper, WxType
         return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg");
       }
       return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg", Paths.get(filePath).toFile());
-    } finally {
-      httpPost.releaseConnection();
     }
   }
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheUploadAuthMaterialRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheUploadAuthMaterialRequestExecutor.java
index ac3ffd7c71..59b35567bb 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheUploadAuthMaterialRequestExecutor.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheUploadAuthMaterialRequestExecutor.java
@@ -9,7 +9,6 @@
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.mime.HttpMultipartMode;
 import org.apache.http.entity.mime.MultipartEntityBuilder;
@@ -24,34 +23,30 @@
  */
 public class ApacheUploadAuthMaterialRequestExecutor extends UploadAuthMaterialRequestExecutor<CloseableHttpClient, HttpHost> {
 
-    public ApacheUploadAuthMaterialRequestExecutor(RequestHttp requestHttp) {
-        super(requestHttp);
-    }
+  public ApacheUploadAuthMaterialRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
 
-    @Override
-    public WxMaUploadAuthMaterialResult execute(String uri, File file, WxType wxType) throws WxErrorException, IOException {
-        HttpPost httpPost = new HttpPost(uri);
-        if (requestHttp.getRequestHttpProxy() != null) {
-            RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
-            httpPost.setConfig(config);
-        }
-        if (file != null) {
-            HttpEntity entity = MultipartEntityBuilder
-                    .create()
-                    .addBinaryBody("media", file)
-                    .setMode(HttpMultipartMode.RFC6532)
-                    .build();
-            httpPost.setEntity(entity);
-        }
-        try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
-            String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
-            WxError error = WxError.fromJson(responseContent, wxType);
-            if (error.getErrorCode() != 0) {
-                throw new WxErrorException(error);
-            }
-            return WxMaUploadAuthMaterialResult.fromJson(responseContent);
-        } finally {
-            httpPost.releaseConnection();
-        }
+  @Override
+  public WxMaUploadAuthMaterialResult execute(String uri, File file, WxType wxType) throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+    if (file != null) {
+      HttpEntity entity = MultipartEntityBuilder
+        .create()
+        .addBinaryBody("media", file)
+        .setMode(HttpMultipartMode.RFC6532)
+        .build();
+      httpPost.setEntity(entity);
+    }
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, wxType);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
     }
+    return WxMaUploadAuthMaterialResult.fromJson(responseContent);
+  }
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheVodSingleUploadRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheVodSingleUploadRequestExecutor.java
index a9ffd1af39..2ca23ae325 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheVodSingleUploadRequestExecutor.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheVodSingleUploadRequestExecutor.java
@@ -8,7 +8,6 @@
 import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.mime.HttpMultipartMode;
 import org.apache.http.entity.mime.MultipartEntityBuilder;
@@ -22,9 +21,8 @@
  */
 public class ApacheVodSingleUploadRequestExecutor extends VodSingleUploadRequestExecutor<CloseableHttpClient, HttpHost> {
 
-  public ApacheVodSingleUploadRequestExecutor(RequestHttp requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) {
+  public ApacheVodSingleUploadRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) {
     super(requestHttp, mediaName, mediaType, coverType, coverData, sourceContext);
-
   }
 
   @Override
@@ -54,15 +52,11 @@ public WxMaVodSingleFileUploadResult execute(String uri, File file, WxType wxTyp
 
       httpPost.setEntity(entityBuilder.build());
     }
-    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
-      String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
-      WxError error = WxError.fromJson(responseContent, wxType);
-      if (error.getErrorCode() != 0) {
-        throw new WxErrorException(error);
-      }
-      return WxMaVodSingleFileUploadResult.fromJson(responseContent);
-    } finally {
-      httpPost.releaseConnection();
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, wxType);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
     }
+    return WxMaVodSingleFileUploadResult.fromJson(responseContent);
   }
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheVodUploadPartRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheVodUploadPartRequestExecutor.java
index e27840cd59..f6c1ec36b6 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheVodUploadPartRequestExecutor.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApacheVodUploadPartRequestExecutor.java
@@ -8,7 +8,6 @@
 import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.mime.HttpMultipartMode;
 import org.apache.http.entity.mime.MultipartEntityBuilder;
@@ -22,7 +21,7 @@
  */
 public class ApacheVodUploadPartRequestExecutor extends VodUploadPartRequestExecutor<CloseableHttpClient, HttpHost> {
 
-  public ApacheVodUploadPartRequestExecutor(RequestHttp requestHttp, String uploadId, Integer partNumber, Integer resourceType) {
+  public ApacheVodUploadPartRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp, String uploadId, Integer partNumber, Integer resourceType) {
     super(requestHttp, uploadId, partNumber, resourceType);
 
   }
@@ -45,15 +44,12 @@ public WxMaVodUploadPartResult execute(String uri, File file, WxType wxType) thr
 
       httpPost.setEntity(entityBuilder.build());
     }
-    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
-      String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
-      WxError error = WxError.fromJson(responseContent, wxType);
-      if (error.getErrorCode() != 0) {
-        throw new WxErrorException(error);
-      }
-      return WxMaVodUploadPartResult.fromJson(responseContent);
-    } finally {
-      httpPost.releaseConnection();
+
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, wxType);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
     }
+    return WxMaVodUploadPartResult.fromJson(responseContent);
   }
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApiSignaturePostRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApiSignaturePostRequestExecutor.java
index 8e3ade961e..c01a7ab5de 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApiSignaturePostRequestExecutor.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/ApiSignaturePostRequestExecutor.java
@@ -1,23 +1,28 @@
 package cn.binarywang.wx.miniapp.executor;
 
 import cn.binarywang.wx.miniapp.bean.WxMaApiResponse;
-import java.io.IOException;
-import java.rmi.RemoteException;
-import java.util.Map;
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.ResponseHandler;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import okhttp3.OkHttpClient;
 import org.jetbrains.annotations.NotNull;
 
+import java.io.IOException;
+import java.rmi.RemoteException;
+import java.util.Map;
+
 public abstract class ApiSignaturePostRequestExecutor<H, P>
     implements RequestExecutor<WxMaApiResponse, WxMaApiResponse> {
 
   protected RequestHttp<H, P> requestHttp;
 
-  public ApiSignaturePostRequestExecutor(RequestHttp requestHttp) {
+  public ApiSignaturePostRequestExecutor(RequestHttp<H, P> requestHttp) {
     this.requestHttp = requestHttp;
   }
 
@@ -54,16 +59,21 @@ public WxMaApiResponse handleResponse(
     return response;
   }
 
-  public static ApiSignaturePostRequestExecutor create(RequestHttp requestHttp) {
+  @SuppressWarnings("unchecked")
+  public static ApiSignaturePostRequestExecutor<?, ?> create(RequestHttp<?, ?> requestHttp) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new ApacheApiSignaturePostRequestExecutor(requestHttp);
+        return new ApacheApiSignaturePostRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp);
       case JODD_HTTP:
-        return new JoddApiSignaturePostRequestExecutor(requestHttp);
+        return new JoddApiSignaturePostRequestExecutor((RequestHttp<HttpConnectionProvider, ProxyInfo>) requestHttp);
       case OK_HTTP:
-        return new OkHttpApiSignaturePostRequestExecutor(requestHttp);
+        return new OkHttpApiSignaturePostRequestExecutor((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp);
+      case HTTP_COMPONENTS:
+        return new HttpComponentsApiSignaturePostRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp);
       default:
-        throw new IllegalArgumentException("非法请求参数");
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsApiSignaturePostRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsApiSignaturePostRequestExecutor.java
new file mode 100644
index 0000000000..23d2231855
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsApiSignaturePostRequestExecutor.java
@@ -0,0 +1,63 @@
+package cn.binarywang.wx.miniapp.executor;
+
+import cn.binarywang.wx.miniapp.bean.WxMaApiResponse;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler;
+import org.apache.hc.client5.http.ClientProtocolException;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+public class HttpComponentsApiSignaturePostRequestExecutor extends ApiSignaturePostRequestExecutor<CloseableHttpClient, HttpHost> {
+
+  public HttpComponentsApiSignaturePostRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
+
+  @Override
+  public WxMaApiResponse execute(
+    String uri, Map<String, String> headers, String postEntity, WxType wxType)
+    throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+
+    if (headers != null) {
+      headers.forEach(httpPost::addHeader);
+    }
+
+    if (postEntity != null) {
+      StringEntity entity = new StringEntity(postEntity, ContentType.APPLICATION_JSON.withCharset(StandardCharsets.UTF_8));
+      httpPost.setEntity(entity);
+    }
+
+    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
+      String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
+      Map<String, String> respHeaders = new HashMap<>();
+      Header[] rHeaders = response.getHeaders();
+      if (rHeaders != null) {
+        for (Header h : rHeaders) {
+          respHeaders.putIfAbsent(h.getName(), h.getValue());
+        }
+      }
+      return this.handleResponse(wxType, responseContent, respHeaders);
+    } catch (HttpException httpException) {
+      throw new ClientProtocolException(httpException.getMessage(), httpException);
+    }
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsQrcodeBytesRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsQrcodeBytesRequestExecutor.java
new file mode 100644
index 0000000000..655296fdaf
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsQrcodeBytesRequestExecutor.java
@@ -0,0 +1,70 @@
+package cn.binarywang.wx.miniapp.executor;
+
+import cn.binarywang.wx.miniapp.bean.AbstractWxMaQrcodeWrapper;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.hc.InputStreamResponseHandler;
+import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler;
+import org.apache.commons.io.IOUtils;
+import org.apache.hc.client5.http.ClientProtocolException;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @author altusea
+ */
+public class HttpComponentsQrcodeBytesRequestExecutor extends QrcodeBytesRequestExecutor<CloseableHttpClient, HttpHost> {
+
+  public HttpComponentsQrcodeBytesRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
+
+  /**
+   * 执行http请求.
+   *
+   * @param uri           uri
+   * @param qrcodeWrapper 数据
+   * @param wxType        微信模块类型
+   * @return 响应结果
+   * @throws WxErrorException 自定义异常
+   * @throws IOException      io异常
+   */
+  @Override
+  public byte[] execute(String uri, AbstractWxMaQrcodeWrapper qrcodeWrapper, WxType wxType) throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      httpPost.setConfig(
+        RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build()
+      );
+    }
+
+    httpPost.setEntity(new StringEntity(qrcodeWrapper.toJson()));
+
+    try (final CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost);
+         final InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) {
+      Header[] contentTypeHeader = response.getHeaders("Content-Type");
+      if (contentTypeHeader != null && contentTypeHeader.length > 0
+        && ContentType.APPLICATION_JSON.getMimeType()
+        .equals(ContentType.parse(contentTypeHeader[0].getValue()).getMimeType())) {
+        String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
+        throw new WxErrorException(WxError.fromJson(responseContent, wxType));
+      }
+
+      return IOUtils.toByteArray(inputStream);
+    } catch (HttpException httpException) {
+      throw new ClientProtocolException(httpException.getMessage(), httpException);
+    }
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsQrcodeFileRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsQrcodeFileRequestExecutor.java
new file mode 100644
index 0000000000..10d01b1cfd
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsQrcodeFileRequestExecutor.java
@@ -0,0 +1,79 @@
+package cn.binarywang.wx.miniapp.executor;
+
+import cn.binarywang.wx.miniapp.bean.AbstractWxMaQrcodeWrapper;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.fs.FileUtils;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.hc.InputStreamResponseHandler;
+import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hc.client5.http.ClientProtocolException;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Paths;
+import java.util.UUID;
+
+/**
+ * @author altusea
+ */
+public class HttpComponentsQrcodeFileRequestExecutor extends QrcodeRequestExecutor<CloseableHttpClient, HttpHost> {
+
+  private final String filePath;
+
+  public HttpComponentsQrcodeFileRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp, String filePath) {
+    super(requestHttp);
+    this.filePath = filePath;
+  }
+
+  /**
+   * 执行http请求.
+   *
+   * @param uri           uri
+   * @param qrcodeWrapper 数据
+   * @param wxType        微信模块类型
+   * @return 响应结果
+   * @throws WxErrorException 自定义异常
+   * @throws IOException      io异常
+   */
+  @Override
+  public File execute(String uri, AbstractWxMaQrcodeWrapper qrcodeWrapper, WxType wxType) throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      httpPost.setConfig(
+        RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build()
+      );
+    }
+
+    httpPost.setEntity(new StringEntity(qrcodeWrapper.toJson(), ContentType.APPLICATION_JSON));
+
+    try (final CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost);
+         final InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) {
+      Header[] contentTypeHeader = response.getHeaders("Content-Type");
+      if (contentTypeHeader != null && contentTypeHeader.length > 0
+        && ContentType.APPLICATION_JSON.getMimeType()
+        .equals(ContentType.parse(contentTypeHeader[0].getValue()).getMimeType())) {
+        String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
+        throw new WxErrorException(WxError.fromJson(responseContent, wxType));
+      }
+      if (StringUtils.isBlank(filePath)) {
+        return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg");
+      }
+      return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg", Paths.get(filePath).toFile());
+    } catch (HttpException httpException) {
+      throw new ClientProtocolException(httpException.getMessage(), httpException);
+    }
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsUploadAuthMaterialRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsUploadAuthMaterialRequestExecutor.java
new file mode 100644
index 0000000000..8bfed3b5fa
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsUploadAuthMaterialRequestExecutor.java
@@ -0,0 +1,51 @@
+package cn.binarywang.wx.miniapp.executor;
+
+import cn.binarywang.wx.miniapp.bean.WxMaUploadAuthMaterialResult;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
+import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * @author altusea
+ */
+public class HttpComponentsUploadAuthMaterialRequestExecutor extends UploadAuthMaterialRequestExecutor<CloseableHttpClient, HttpHost> {
+
+  public HttpComponentsUploadAuthMaterialRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
+
+  @Override
+  public WxMaUploadAuthMaterialResult execute(String uri, File file, WxType wxType) throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+    if (file != null) {
+      HttpEntity entity = MultipartEntityBuilder
+        .create()
+        .addBinaryBody("media", file)
+        .setMode(HttpMultipartMode.EXTENDED)
+        .build();
+      httpPost.setEntity(entity);
+    }
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, wxType);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
+    }
+    return WxMaUploadAuthMaterialResult.fromJson(responseContent);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsVodSingleUploadRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsVodSingleUploadRequestExecutor.java
new file mode 100644
index 0000000000..3f9139d459
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsVodSingleUploadRequestExecutor.java
@@ -0,0 +1,59 @@
+package cn.binarywang.wx.miniapp.executor;
+
+import cn.binarywang.wx.miniapp.bean.vod.WxMaVodSingleFileUploadResult;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
+import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.File;
+import java.io.IOException;
+
+public class HttpComponentsVodSingleUploadRequestExecutor extends VodSingleUploadRequestExecutor<CloseableHttpClient, HttpHost> {
+
+  public HttpComponentsVodSingleUploadRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) {
+    super(requestHttp, mediaName, mediaType, coverType, coverData, sourceContext);
+  }
+
+  @Override
+  public WxMaVodSingleFileUploadResult execute(String uri, File file, WxType wxType) throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+    if (file != null) {
+      MultipartEntityBuilder entityBuilder = MultipartEntityBuilder
+        .create()
+        .setMode(HttpMultipartMode.EXTENDED)
+        .addTextBody("media_name", mediaName)
+        .addTextBody("media_type", mediaType)
+        .addBinaryBody("media_data", file);
+
+      if (coverType != null) {
+        entityBuilder.addTextBody("cover_type", coverType);
+      }
+      if (coverData != null) {
+        entityBuilder.addBinaryBody("cover_data", coverData);
+      }
+      if (sourceContext != null) {
+        entityBuilder.addTextBody("source_context", sourceContext);
+      }
+
+      httpPost.setEntity(entityBuilder.build());
+    }
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, wxType);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
+    }
+    return WxMaVodSingleFileUploadResult.fromJson(responseContent);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsVodUploadPartRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsVodUploadPartRequestExecutor.java
new file mode 100644
index 0000000000..eb2cf8e9db
--- /dev/null
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/HttpComponentsVodUploadPartRequestExecutor.java
@@ -0,0 +1,52 @@
+package cn.binarywang.wx.miniapp.executor;
+
+import cn.binarywang.wx.miniapp.bean.vod.WxMaVodUploadPartResult;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
+import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.File;
+import java.io.IOException;
+
+public class HttpComponentsVodUploadPartRequestExecutor extends VodUploadPartRequestExecutor<CloseableHttpClient, HttpHost> {
+
+  public HttpComponentsVodUploadPartRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp, String uploadId, Integer partNumber, Integer resourceType) {
+    super(requestHttp, uploadId, partNumber, resourceType);
+
+  }
+
+  @Override
+  public WxMaVodUploadPartResult execute(String uri, File file, WxType wxType) throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+    if (file != null) {
+      MultipartEntityBuilder entityBuilder = MultipartEntityBuilder
+        .create()
+        .setMode(HttpMultipartMode.EXTENDED)
+        .addTextBody("upload_id", uploadId)
+        .addTextBody("part_number", String.valueOf(partNumber))
+        .addTextBody("resource_type", String.valueOf(resourceType))
+        .addBinaryBody("data", file);
+
+      httpPost.setEntity(entityBuilder.build());
+    }
+
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, wxType);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
+    }
+    return WxMaVodUploadPartResult.fromJson(responseContent);
+  }
+}
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddApiSignaturePostRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddApiSignaturePostRequestExecutor.java
index b7568bc21d..d8724a6ac8 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddApiSignaturePostRequestExecutor.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddApiSignaturePostRequestExecutor.java
@@ -20,7 +20,7 @@ public class JoddApiSignaturePostRequestExecutor
   private static final Logger logger =
       LoggerFactory.getLogger(JoddApiSignaturePostRequestExecutor.class);
 
-  public JoddApiSignaturePostRequestExecutor(RequestHttp<?, ?> requestHttp) {
+  public JoddApiSignaturePostRequestExecutor(RequestHttp<HttpConnectionProvider, ProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpQrcodeFileRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpQrcodeFileRequestExecutor.java
index d63e29c5d4..b121932d74 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpQrcodeFileRequestExecutor.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpQrcodeFileRequestExecutor.java
@@ -11,8 +11,6 @@
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.fs.FileUtils;
 import me.chanjar.weixin.common.util.http.RequestHttp;
-import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
-import okhttp3.*;
 import org.apache.commons.lang3.StringUtils;
 
 import java.io.ByteArrayInputStream;
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpUploadAuthMaterialRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpUploadAuthMaterialRequestExecutor.java
index cff63972e3..874a96f2c4 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpUploadAuthMaterialRequestExecutor.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpUploadAuthMaterialRequestExecutor.java
@@ -20,7 +20,7 @@
  */
 public class JoddHttpUploadAuthMaterialRequestExecutor extends UploadAuthMaterialRequestExecutor<HttpConnectionProvider, ProxyInfo> {
 
-    public JoddHttpUploadAuthMaterialRequestExecutor(RequestHttp requestHttp) {
+    public JoddHttpUploadAuthMaterialRequestExecutor(RequestHttp<HttpConnectionProvider, ProxyInfo> requestHttp) {
         super(requestHttp);
     }
 
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpVodSingleUploadRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpVodSingleUploadRequestExecutor.java
index ed47a9fc67..cb71076c60 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpVodSingleUploadRequestExecutor.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpVodSingleUploadRequestExecutor.java
@@ -19,7 +19,7 @@
  */
 public class JoddHttpVodSingleUploadRequestExecutor extends VodSingleUploadRequestExecutor<HttpConnectionProvider, ProxyInfo> {
 
-  public JoddHttpVodSingleUploadRequestExecutor(RequestHttp requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) {
+  public JoddHttpVodSingleUploadRequestExecutor(RequestHttp<HttpConnectionProvider, ProxyInfo> requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) {
     super(requestHttp, mediaName, mediaType, coverType, coverData, sourceContext);
   }
 
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpVodUploadPartRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpVodUploadPartRequestExecutor.java
index 36e53b66bf..e86a1d5b98 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpVodUploadPartRequestExecutor.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/JoddHttpVodUploadPartRequestExecutor.java
@@ -19,7 +19,7 @@
  */
 public class JoddHttpVodUploadPartRequestExecutor extends VodUploadPartRequestExecutor<HttpConnectionProvider, ProxyInfo> {
 
-  public JoddHttpVodUploadPartRequestExecutor(RequestHttp requestHttp, String uploadId, Integer partNumber, Integer resourceType) {
+  public JoddHttpVodUploadPartRequestExecutor(RequestHttp<HttpConnectionProvider, ProxyInfo> requestHttp, String uploadId, Integer partNumber, Integer resourceType) {
     super(requestHttp, uploadId, partNumber, resourceType);
 
   }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpApiSignaturePostRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpApiSignaturePostRequestExecutor.java
index 10c75a26bd..f9d1262821 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpApiSignaturePostRequestExecutor.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpApiSignaturePostRequestExecutor.java
@@ -18,7 +18,7 @@ public class OkHttpApiSignaturePostRequestExecutor
   private static final Logger logger =
       LoggerFactory.getLogger(OkHttpApiSignaturePostRequestExecutor.class);
 
-  public OkHttpApiSignaturePostRequestExecutor(RequestHttp<?, ?> requestHttp) {
+  public OkHttpApiSignaturePostRequestExecutor(RequestHttp<OkHttpClient, OkHttpProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpUploadAuthMaterialRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpUploadAuthMaterialRequestExecutor.java
index 698fb78894..67d0d99b3f 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpUploadAuthMaterialRequestExecutor.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpUploadAuthMaterialRequestExecutor.java
@@ -17,7 +17,7 @@
  */
 public class OkHttpUploadAuthMaterialRequestExecutor extends UploadAuthMaterialRequestExecutor<OkHttpClient, OkHttpProxyInfo> {
 
-    public OkHttpUploadAuthMaterialRequestExecutor(RequestHttp requestHttp) {
+    public OkHttpUploadAuthMaterialRequestExecutor(RequestHttp<OkHttpClient, OkHttpProxyInfo> requestHttp) {
         super(requestHttp);
     }
 
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpVodSingleUploadRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpVodSingleUploadRequestExecutor.java
index 78fbdd3d25..d6e8a6880f 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpVodSingleUploadRequestExecutor.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpVodSingleUploadRequestExecutor.java
@@ -16,7 +16,7 @@
  */
 public class OkHttpVodSingleUploadRequestExecutor extends VodSingleUploadRequestExecutor<OkHttpClient, OkHttpProxyInfo> {
 
-  public OkHttpVodSingleUploadRequestExecutor(RequestHttp requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) {
+  public OkHttpVodSingleUploadRequestExecutor(RequestHttp<OkHttpClient, OkHttpProxyInfo> requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) {
     super(requestHttp, mediaName, mediaType, coverType, coverData, sourceContext);
   }
 
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpVodUploadPartRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpVodUploadPartRequestExecutor.java
index c9e991d082..59d4aa932d 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpVodUploadPartRequestExecutor.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/OkHttpVodUploadPartRequestExecutor.java
@@ -16,7 +16,7 @@
  */
 public class OkHttpVodUploadPartRequestExecutor extends VodUploadPartRequestExecutor<OkHttpClient, OkHttpProxyInfo> {
 
-  public OkHttpVodUploadPartRequestExecutor(RequestHttp requestHttp, String uploadId, Integer partNumber, Integer resourceType) {
+  public OkHttpVodUploadPartRequestExecutor(RequestHttp<OkHttpClient, OkHttpProxyInfo> requestHttp, String uploadId, Integer partNumber, Integer resourceType) {
     super(requestHttp, uploadId, partNumber, resourceType);
 
   }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/QrcodeBytesRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/QrcodeBytesRequestExecutor.java
index a4a5112565..4d95a6daae 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/QrcodeBytesRequestExecutor.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/QrcodeBytesRequestExecutor.java
@@ -6,6 +6,8 @@
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.ResponseHandler;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import okhttp3.OkHttpClient;
 
 import java.io.IOException;
 
@@ -16,7 +18,7 @@ public abstract class QrcodeBytesRequestExecutor<H, P> implements RequestExecuto
 
   protected RequestHttp<H, P> requestHttp;
 
-  public QrcodeBytesRequestExecutor(RequestHttp requestHttp) {
+  public QrcodeBytesRequestExecutor(RequestHttp<H, P> requestHttp) {
     this.requestHttp = requestHttp;
   }
 
@@ -25,16 +27,19 @@ public void execute(String uri, AbstractWxMaQrcodeWrapper data, ResponseHandler<
     handler.handle(this.execute(uri, data, wxType));
   }
 
-  public static RequestExecutor<byte[], AbstractWxMaQrcodeWrapper> create(RequestHttp requestHttp) {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<byte[], AbstractWxMaQrcodeWrapper> create(RequestHttp<?, ?> requestHttp) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new ApacheQrcodeBytesRequestExecutor(requestHttp);
-      case JODD_HTTP:
-        return null;
+        return new ApacheQrcodeBytesRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp);
       case OK_HTTP:
-        return new OkHttpQrcodeBytesRequestExecutor(requestHttp);
+        return new OkHttpQrcodeBytesRequestExecutor((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp);
+      case HTTP_COMPONENTS:
+        return new HttpComponentsQrcodeBytesRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp);
       default:
-        return null;
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/QrcodeRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/QrcodeRequestExecutor.java
index bf85004ac5..ec1d0fd158 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/QrcodeRequestExecutor.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/QrcodeRequestExecutor.java
@@ -6,6 +6,10 @@
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.ResponseHandler;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import okhttp3.OkHttpClient;
+import org.apache.http.HttpHost;
+import org.apache.http.impl.client.CloseableHttpClient;
 
 import java.io.File;
 import java.io.IOException;
@@ -25,29 +29,34 @@ public void execute(String uri, AbstractWxMaQrcodeWrapper data, ResponseHandler<
     handler.handle(this.execute(uri, data, wxType));
   }
 
-
-  public static RequestExecutor<File, AbstractWxMaQrcodeWrapper> create(RequestHttp requestHttp, String path) {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<File, AbstractWxMaQrcodeWrapper> create(RequestHttp<?, ?> requestHttp, String path) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new ApacheQrcodeFileRequestExecutor(requestHttp, path);
+        return new ApacheQrcodeFileRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp, path);
       case OK_HTTP:
-        return new OkHttpQrcodeFileRequestExecutor(requestHttp, path);
-      case JODD_HTTP:
+        return new OkHttpQrcodeFileRequestExecutor((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp, path);
+      case HTTP_COMPONENTS:
+        return new HttpComponentsQrcodeFileRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp, path);
       default:
-        return null;
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 
-  public static RequestExecutor<File, AbstractWxMaQrcodeWrapper> create(RequestHttp requestHttp) {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<File, AbstractWxMaQrcodeWrapper> create(RequestHttp<?, ?> requestHttp) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new ApacheQrcodeFileRequestExecutor(requestHttp, null);
-      case JODD_HTTP:
-        return null;
+        return new ApacheQrcodeFileRequestExecutor((RequestHttp<CloseableHttpClient, HttpHost>) requestHttp, null);
       case OK_HTTP:
-        return new OkHttpQrcodeFileRequestExecutor(requestHttp, null);
+        return new OkHttpQrcodeFileRequestExecutor((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp, null);
+      case HTTP_COMPONENTS:
+        return new HttpComponentsQrcodeFileRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp, null);
       default:
-        return null;
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/UploadAuthMaterialRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/UploadAuthMaterialRequestExecutor.java
index 35bdcd9ed1..4d232ced21 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/UploadAuthMaterialRequestExecutor.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/UploadAuthMaterialRequestExecutor.java
@@ -1,11 +1,15 @@
 package cn.binarywang.wx.miniapp.executor;
 
 import cn.binarywang.wx.miniapp.bean.WxMaUploadAuthMaterialResult;
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.ResponseHandler;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import okhttp3.OkHttpClient;
 
 import java.io.File;
 import java.io.IOException;
@@ -19,27 +23,32 @@
  * @since 2024/01/07
  */
 public abstract class UploadAuthMaterialRequestExecutor<H, P> implements RequestExecutor<WxMaUploadAuthMaterialResult, File> {
-    protected RequestHttp<H, P> requestHttp;
+  protected RequestHttp<H, P> requestHttp;
 
-    public UploadAuthMaterialRequestExecutor(RequestHttp requestHttp) {
-        this.requestHttp = requestHttp;
-    }
+  public UploadAuthMaterialRequestExecutor(RequestHttp<H, P> requestHttp) {
+    this.requestHttp = requestHttp;
+  }
 
-    @Override
-    public void execute(String uri, File data, ResponseHandler<WxMaUploadAuthMaterialResult> handler, WxType wxType) throws WxErrorException, IOException {
-        handler.handle(this.execute(uri, data, wxType));
-    }
+  @Override
+  public void execute(String uri, File data, ResponseHandler<WxMaUploadAuthMaterialResult> handler, WxType wxType) throws WxErrorException, IOException {
+    handler.handle(this.execute(uri, data, wxType));
+  }
 
-    public static RequestExecutor<WxMaUploadAuthMaterialResult, File> create(RequestHttp requestHttp) {
-        switch (requestHttp.getRequestType()) {
-            case APACHE_HTTP:
-                return new ApacheUploadAuthMaterialRequestExecutor(requestHttp);
-            case JODD_HTTP:
-                return new JoddHttpUploadAuthMaterialRequestExecutor(requestHttp);
-            case OK_HTTP:
-                return new OkHttpUploadAuthMaterialRequestExecutor(requestHttp);
-            default:
-                return null;
-        }
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<WxMaUploadAuthMaterialResult, File> create(RequestHttp<?, ?> requestHttp) {
+    switch (requestHttp.getRequestType()) {
+      case APACHE_HTTP:
+        return new ApacheUploadAuthMaterialRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp);
+      case JODD_HTTP:
+        return new JoddHttpUploadAuthMaterialRequestExecutor((RequestHttp<HttpConnectionProvider, ProxyInfo>) requestHttp);
+      case OK_HTTP:
+        return new OkHttpUploadAuthMaterialRequestExecutor((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp);
+      case HTTP_COMPONENTS:
+        return new HttpComponentsUploadAuthMaterialRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp);
+      default:
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
+  }
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/VodSingleUploadRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/VodSingleUploadRequestExecutor.java
index 40c73b0064..578fc8949c 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/VodSingleUploadRequestExecutor.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/VodSingleUploadRequestExecutor.java
@@ -1,11 +1,15 @@
 package cn.binarywang.wx.miniapp.executor;
 
 import cn.binarywang.wx.miniapp.bean.vod.WxMaVodSingleFileUploadResult;
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.ResponseHandler;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import okhttp3.OkHttpClient;
 
 import java.io.File;
 import java.io.IOException;
@@ -27,7 +31,7 @@ public abstract class VodSingleUploadRequestExecutor<H, P> implements RequestExe
   protected String sourceContext;
   protected File coverData;
 
-  public VodSingleUploadRequestExecutor(RequestHttp requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) {
+  public VodSingleUploadRequestExecutor(RequestHttp<H, P> requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) {
     this.requestHttp = requestHttp;
     this.mediaName = mediaName;
     this.mediaType = mediaType;
@@ -37,16 +41,24 @@ public VodSingleUploadRequestExecutor(RequestHttp requestHttp, String mediaName,
 
   }
 
-  public static RequestExecutor<WxMaVodSingleFileUploadResult, File> create(RequestHttp requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<WxMaVodSingleFileUploadResult, File> create(RequestHttp<?, ?> requestHttp, String mediaName, String mediaType, String coverType, File coverData, String sourceContext) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new ApacheVodSingleUploadRequestExecutor(requestHttp, mediaName, mediaType, coverType, coverData, sourceContext);
+        return new ApacheVodSingleUploadRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp,
+          mediaName, mediaType, coverType, coverData, sourceContext);
       case JODD_HTTP:
-        return new JoddHttpVodSingleUploadRequestExecutor(requestHttp, mediaName, mediaType, coverType, coverData, sourceContext);
+        return new JoddHttpVodSingleUploadRequestExecutor((RequestHttp<HttpConnectionProvider, ProxyInfo>) requestHttp, mediaName, mediaType, coverType, coverData, sourceContext);
       case OK_HTTP:
-        return new OkHttpVodSingleUploadRequestExecutor(requestHttp, mediaName, mediaType, coverType, coverData, sourceContext);
+        return new OkHttpVodSingleUploadRequestExecutor(
+          (RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp, mediaName, mediaType, coverType, coverData, sourceContext);
+        case HTTP_COMPONENTS:
+          return new HttpComponentsVodSingleUploadRequestExecutor(
+            (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp,
+            mediaName, mediaType, coverType, coverData, sourceContext);
       default:
-        return null;
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 
@@ -55,5 +67,4 @@ public void execute(String uri, File data, ResponseHandler<WxMaVodSingleFileUplo
     handler.handle(this.execute(uri, data, wxType));
   }
 
-
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/VodUploadPartRequestExecutor.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/VodUploadPartRequestExecutor.java
index 96c6914acf..d3d8c6dfaa 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/VodUploadPartRequestExecutor.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/executor/VodUploadPartRequestExecutor.java
@@ -1,11 +1,15 @@
 package cn.binarywang.wx.miniapp.executor;
 
 import cn.binarywang.wx.miniapp.bean.vod.WxMaVodUploadPartResult;
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.ResponseHandler;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import okhttp3.OkHttpClient;
 
 import java.io.File;
 import java.io.IOException;
@@ -19,7 +23,7 @@ public abstract class VodUploadPartRequestExecutor<H, P> implements RequestExecu
   protected Integer partNumber;
   protected Integer resourceType;
 
-  public VodUploadPartRequestExecutor(RequestHttp requestHttp, String uploadId, Integer partNumber, Integer resourceType) {
+  public VodUploadPartRequestExecutor(RequestHttp<H, P> requestHttp, String uploadId, Integer partNumber, Integer resourceType) {
     this.requestHttp = requestHttp;
     this.uploadId = uploadId;
     this.partNumber = partNumber;
@@ -27,16 +31,23 @@ public VodUploadPartRequestExecutor(RequestHttp requestHttp, String uploadId, In
 
   }
 
-  public static RequestExecutor<WxMaVodUploadPartResult, File> create(RequestHttp requestHttp, String uploadId, Integer partNumber, Integer resourceType) {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<WxMaVodUploadPartResult, File> create(RequestHttp<?, ?> requestHttp, String uploadId, Integer partNumber, Integer resourceType) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new ApacheVodUploadPartRequestExecutor(requestHttp, uploadId, partNumber, resourceType);
+        return new ApacheVodUploadPartRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp,
+          uploadId, partNumber, resourceType);
       case JODD_HTTP:
-        return new JoddHttpVodUploadPartRequestExecutor(requestHttp, uploadId, partNumber, resourceType);
+        return new JoddHttpVodUploadPartRequestExecutor((RequestHttp<HttpConnectionProvider, ProxyInfo>) requestHttp, uploadId, partNumber, resourceType);
       case OK_HTTP:
-        return new OkHttpVodUploadPartRequestExecutor(requestHttp, uploadId, partNumber, resourceType);
+        return new OkHttpVodUploadPartRequestExecutor((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp, uploadId, partNumber, resourceType);
+      case HTTP_COMPONENTS:
+        return new HttpComponentsVodUploadPartRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp,
+          uploadId, partNumber, resourceType);
       default:
-        return null;
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 
@@ -45,5 +56,4 @@ public void execute(String uri, File data, ResponseHandler<WxMaVodUploadPartResu
     handler.handle(this.execute(uri, data, wxType));
   }
 
-
 }
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaCodeVersionDistributionGsonAdapter.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaCodeVersionDistributionGsonAdapter.java
index 018be6b046..746d261170 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaCodeVersionDistributionGsonAdapter.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaCodeVersionDistributionGsonAdapter.java
@@ -33,7 +33,7 @@ public WxMaCodeVersionDistribution deserialize(JsonElement json, Type type, Json
 
   private Map<String, Float> getAsMap(JsonObject object, String memberName) {
     JsonArray array = object.getAsJsonArray(memberName);
-    if (array != null && array.size() > 0) {
+    if (array != null && !array.isEmpty()) {
       Map<String, Float> map = new LinkedHashMap<>(array.size());
       for (JsonElement element : array) {
         JsonObject elementObject = element.getAsJsonObject();
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaRetainInfoGsonAdapter.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaRetainInfoGsonAdapter.java
index 2e71f9eb4e..d316bbfeb1 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaRetainInfoGsonAdapter.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaRetainInfoGsonAdapter.java
@@ -35,7 +35,7 @@ public WxMaRetainInfo deserialize(JsonElement json, Type type, JsonDeserializati
 
   private Map<Integer, Integer> getAsMap(JsonObject object, String memberName) {
     JsonArray array = object.getAsJsonArray(memberName);
-    if (array != null && array.size() > 0) {
+    if (array != null && !array.isEmpty()) {
       Map<Integer, Integer> map = new LinkedHashMap<>(array.size());
       for (JsonElement element : array) {
         JsonObject elementObject = element.getAsJsonObject();
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaSubscribeMsgEventJsonAdapter.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaSubscribeMsgEventJsonAdapter.java
index 377f8e35ef..f875be5a9e 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaSubscribeMsgEventJsonAdapter.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaSubscribeMsgEventJsonAdapter.java
@@ -24,7 +24,7 @@ public WxMaSubscribeMsgEvent.WxMaSubscribeMsgEventJson deserialize(JsonElement j
     WxMaSubscribeMsgEvent.WxMaSubscribeMsgEventJson result = new WxMaSubscribeMsgEvent.WxMaSubscribeMsgEventJson();
     if (json.isJsonArray()) {
       JsonArray array = json.getAsJsonArray();
-      if (array.size() > 0) {
+      if (!array.isEmpty()) {
         JsonObject obj = array.get(0).getAsJsonObject();
         MsgEventTypeEnum eventType = detectMsgEventType(obj);
         for (int i = 0; i < array.size(); ++i) {
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaUserPortraitGsonAdapter.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaUserPortraitGsonAdapter.java
index c99fd67ba3..edcc272ae1 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaUserPortraitGsonAdapter.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/json/adaptor/WxMaUserPortraitGsonAdapter.java
@@ -50,7 +50,7 @@ private WxMaUserPortrait.Item getPortraitItem(JsonObject object) {
 
   private Map<String, Long> getAsMap(JsonObject object, String memberName) {
     JsonArray array = object.getAsJsonArray(memberName);
-    if (array != null && array.size() > 0) {
+    if (array != null && !array.isEmpty()) {
       Map<String, Long> map = new LinkedHashMap<>(array.size());
       for (JsonElement element : array) {
         JsonObject elementObject = element.getAsJsonObject();
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java
index 6cd603929d..fd369f517a 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/message/WxMaMessageRouter.java
@@ -7,7 +7,6 @@
 import lombok.Data;
 import me.chanjar.weixin.common.api.WxErrorExceptionHandler;
 import me.chanjar.weixin.common.api.WxMessageDuplicateChecker;
-import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker;
 import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateCheckerSingleton;
 import me.chanjar.weixin.common.session.InternalSession;
 import me.chanjar.weixin.common.session.InternalSessionManager;
@@ -125,7 +124,7 @@ public WxMaXmlOutMessage route(final WxMaMessage wxMessage, final Map<String, Ob
       }
     }
 
-    if (matchRules.size() == 0) {
+    if (matchRules.isEmpty()) {
       return null;
     }
 
@@ -152,7 +151,7 @@ public WxMaXmlOutMessage route(final WxMaMessage wxMessage, final Map<String, Ob
       }
     }
 
-    if (futures.size() > 0) {
+    if (!futures.isEmpty()) {
       this.executorService.submit(() -> {
         for (Future<?> future : futures) {
           try {
@@ -173,7 +172,7 @@ public WxMaXmlOutMessage route(final WxMaMessage wxMessage) {
     return this.route(wxMessage, new HashMap<>(2));
   }
 
-  private boolean isMsgDuplicated(WxMaMessage wxMessage) {
+  protected boolean isMsgDuplicated(WxMaMessage wxMessage) {
     StringBuilder messageId = new StringBuilder();
     if (wxMessage.getMsgId() == null) {
       messageId.append(wxMessage.getCreateTime())
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/WxMaConfigHolder.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/WxMaConfigHolder.java
index 15dd8654c0..68bd6286d6 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/WxMaConfigHolder.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/WxMaConfigHolder.java
@@ -7,12 +7,7 @@
  * created on  2020-08-16
  */
 public class WxMaConfigHolder {
-  private static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<String>() {
-    @Override
-    protected String initialValue() {
-      return "default";
-    }
-  };
+  private static final ThreadLocal<String> THREAD_LOCAL = ThreadLocal.withInitial(() -> "default");
 
   public static String get() {
     return THREAD_LOCAL.get();
diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtils.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtils.java
index 0222265e44..08346dbbb8 100644
--- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtils.java
+++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtils.java
@@ -10,8 +10,6 @@
 import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
 
-import com.google.common.base.CharMatcher;
-import com.google.common.io.BaseEncoding;
 import me.chanjar.weixin.common.error.WxRuntimeException;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.lang3.StringUtils;
diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaIntracityServiceImpleTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaIntracityServiceImpleTest.java
index 9828542a46..e16fc424c7 100644
--- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaIntracityServiceImpleTest.java
+++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaIntracityServiceImpleTest.java
@@ -254,8 +254,8 @@ public void testOrderRelatived() throws Exception {
       cargo.setCargoPrice(10000);
       cargo.setCargoWeight(1000);
       request.setCargo(cargo);
-      WxMaAddOrderResponse response = wxService.getIntracityService().preAddOrder(request);
-      logger.debug("查询运费返回 {}， 预估运费{}元", response, response.getFee() / 100.0);
+      WxMaPreAddOrderResponse response = wxService.getIntracityService().preAddOrder(request);
+      logger.debug("查询运费返回 {}， 预估运费{}元", response, response.getEstFee() / 100.0);
     }
     String wxOrderId = null;
     {
diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaXPayServiceImplTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaXPayServiceImplTest.java
index 0c980fda55..1533f2a0b6 100644
--- a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaXPayServiceImplTest.java
+++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/api/impl/WxMaXPayServiceImplTest.java
@@ -1,6 +1,7 @@
 package cn.binarywang.wx.miniapp.api.impl;
 
 import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.bean.WxMaBaseResponse;
 import cn.binarywang.wx.miniapp.bean.xpay.*;
 import cn.binarywang.wx.miniapp.constant.WxMaConstants;
 import cn.binarywang.wx.miniapp.test.ApiTestModule;
@@ -119,6 +120,7 @@ public void testDownloadBill() throws Exception {
     WxMaXPayDownloadBillResponse response = this.wxService.getWxMaXPayService().downloadBill(request, sigParams);
     assertNotNull(response);
   }
+
   @Test
   public void testRefundOrder() throws Exception {
     WxMaXPayRefundOrderRequest request = WxMaXPayRefundOrderRequest.builder()
@@ -217,4 +219,209 @@ public void testQueryPublishGoods() throws Exception {
     assertNotNull(response);
   }
 
+  @Test
+  public void testQueryBizBalance() throws Exception {
+    WxMaXPayQueryBizBalanceRequest request = WxMaXPayQueryBizBalanceRequest.builder()
+      .env(WxMaConstants.XPayEnv.PRODUCT)
+      .build();
+    WxMaXPaySigParams sigParams = new WxMaXPaySigParams();
+    sigParams.setAppKey("");
+    WxMaXPayQueryBizBalanceResponse response = this.wxService.getWxMaXPayService().queryBizBalance(request, sigParams);
+    assertNotNull(response);
+  }
+
+  @Test
+  public void testQueryTransferAccount() throws Exception {
+    WxMaXPayQueryTransferAccountRequest request = WxMaXPayQueryTransferAccountRequest.builder()
+      .env(WxMaConstants.XPayEnv.PRODUCT)
+      .build();
+    WxMaXPaySigParams sigParams = new WxMaXPaySigParams();
+    sigParams.setAppKey("");
+    WxMaXPayQueryTransferAccountResponse response = this.wxService.getWxMaXPayService().queryTransferAccount(request, sigParams);
+    assertNotNull(response);
+  }
+
+  @Test
+  public void testQueryAdverFunds() throws Exception {
+    WxMaXPayQueryAdverFundsRequest request = WxMaXPayQueryAdverFundsRequest.builder()
+      .env(WxMaConstants.XPayEnv.PRODUCT)
+      .page(0)
+      .pageSize(10)
+      .filter(new WxMaXPayQueryAdverFundsRequest.Filter())
+      .build();
+    WxMaXPaySigParams sigParams = new WxMaXPaySigParams();
+    sigParams.setAppKey("");
+    WxMaXPayQueryAdverFundsResponse response = this.wxService.getWxMaXPayService().queryAdverFunds(request, sigParams);
+    assertNotNull(response);
+  }
+
+  @Test
+  public void testCreateFundsBill() throws Exception {
+    WxMaXPayCreateFundsBillRequest request = WxMaXPayCreateFundsBillRequest.builder()
+      .env(WxMaConstants.XPayEnv.PRODUCT)
+      .transferAmount(0)
+      .transferAccountUid(0L)
+      .transferAccountName("")
+      .transferAccountAgencyId(0)
+      .requestId("")
+      .settleBegin(0L)
+      .settleEnd(0L)
+      .authorizeAdvertise(0)
+      .fundType(0)
+      .build();
+    WxMaXPaySigParams sigParams = new WxMaXPaySigParams();
+    sigParams.setAppKey("");
+    WxMaXPayCreateFundsBillResponse response = this.wxService.getWxMaXPayService().createFundsBill(request, sigParams);
+    assertNotNull(response);
+  }
+
+  @Test
+  public void testBindTransferAccount() throws Exception {
+    WxMaXPayBindTransferAccountRequest request = WxMaXPayBindTransferAccountRequest.builder()
+      .env(WxMaConstants.XPayEnv.PRODUCT)
+      .transferAccountOrgName("")
+      .transferAccountUid(0L)
+      .build();
+    WxMaXPaySigParams sigParams = new WxMaXPaySigParams();
+    sigParams.setAppKey("");
+    WxMaBaseResponse response = this.wxService.getWxMaXPayService().bindTransferAccount(request, sigParams);
+    assertNotNull(response);
+  }
+
+  @Test
+  public void testQueryFundsBill() throws Exception {
+    WxMaXPayQueryFundsBillRequest request = WxMaXPayQueryFundsBillRequest.builder()
+      .env(WxMaConstants.XPayEnv.PRODUCT)
+      .page(0)
+      .pageSize(10)
+      .filter(new WxMaXPayQueryFundsBillRequest.Filter())
+      .build();
+    WxMaXPaySigParams sigParams = new WxMaXPaySigParams();
+    sigParams.setAppKey("");
+    WxMaXPayQueryFundsBillResponse response = this.wxService.getWxMaXPayService().queryFundsBill(request, sigParams);
+    assertNotNull(response);
+  }
+
+
+  @Test
+  public void testQueryRecoverBill() throws Exception {
+    WxMaXPayQueryRecoverBillRequest request = WxMaXPayQueryRecoverBillRequest.builder()
+      .env(WxMaConstants.XPayEnv.PRODUCT)
+      .page(0)
+      .pageSize(10)
+      .filter(new WxMaXPayQueryRecoverBillRequest.Filter())
+      .build();
+    WxMaXPaySigParams sigParams = new WxMaXPaySigParams();
+    sigParams.setAppKey("");
+    WxMaXPayQueryRecoverBillResponse response = this.wxService.getWxMaXPayService().queryRecoverBill(request, sigParams);
+    assertNotNull(response);
+  }
+
+  @Test
+  public void testGetComplaintList() throws Exception {
+    WxMaXPayGetComplaintListRequest request = WxMaXPayGetComplaintListRequest.builder()
+      .env(WxMaConstants.XPayEnv.PRODUCT)
+      .beginDate("")
+      .endDate("")
+      .offset(0)
+      .limit(10)
+      .build();
+    WxMaXPaySigParams sigParams = new WxMaXPaySigParams();
+    sigParams.setAppKey("");
+    WxMaXPayGetComplaintListResponse response = this.wxService.getWxMaXPayService().getComplaintList(request, sigParams);
+    assertNotNull(response);
+  }
+
+  @Test
+  public void testGetComplaintDetail() throws Exception {
+    WxMaXPayGetComplaintDetailRequest request = WxMaXPayGetComplaintDetailRequest.builder()
+      .env(WxMaConstants.XPayEnv.PRODUCT)
+      .complaintId("")
+      .build();
+    WxMaXPaySigParams sigParams = new WxMaXPaySigParams();
+    sigParams.setAppKey("");
+    WxMaXPayGetComplaintDetailResponse response = this.wxService.getWxMaXPayService().getComplaintDetail(request, sigParams);
+    assertNotNull(response);
+  }
+
+  @Test
+  public void testGetNegotiationHistory() throws Exception {
+    WxMaXPayGetNegotiationHistoryRequest request = WxMaXPayGetNegotiationHistoryRequest.builder()
+      .env(WxMaConstants.XPayEnv.PRODUCT)
+      .limit(10)
+      .offset(0)
+      .complaintId("")
+      .build();
+    WxMaXPaySigParams sigParams = new WxMaXPaySigParams();
+    sigParams.setAppKey("");
+    WxMaXPayGetNegotiationHistoryResponse response = this.wxService.getWxMaXPayService().getNegotiationHistory(request, sigParams);
+    assertNotNull(response);
+  }
+
+  @Test
+  public void testResponseComplaint() throws Exception {
+    WxMaXPayResponseComplaintRequest request = WxMaXPayResponseComplaintRequest.builder()
+      .env(WxMaConstants.XPayEnv.PRODUCT)
+      .complaintId("")
+      .responseContent("")
+      .responseImages(new ArrayList<>())
+      .build();
+    WxMaXPaySigParams sigParams = new WxMaXPaySigParams();
+    sigParams.setAppKey("");
+    WxMaBaseResponse response = this.wxService.getWxMaXPayService().responseComplaint(request, sigParams);
+    assertNotNull(response);
+  }
+
+  @Test
+  public void testCompleteComplaint() throws Exception {
+    WxMaXPayCompleteComplaintRequest request = WxMaXPayCompleteComplaintRequest.builder()
+      .env(WxMaConstants.XPayEnv.PRODUCT)
+      .complaintId("")
+      .build();
+    WxMaXPaySigParams sigParams = new WxMaXPaySigParams();
+    sigParams.setAppKey("");
+    WxMaBaseResponse response = this.wxService.getWxMaXPayService().completeComplaint(request, sigParams);
+    assertNotNull(response);
+  }
+
+  @Test
+  public void testUploadVpFile() throws Exception {
+    WxMaXPayUploadVpFileRequest request = WxMaXPayUploadVpFileRequest.builder()
+      .env(WxMaConstants.XPayEnv.PRODUCT)
+      .base64Img("")
+      .fileName("")
+      .imgUrl("")
+      .build();
+    WxMaXPaySigParams sigParams = new WxMaXPaySigParams();
+    sigParams.setAppKey("");
+    WxMaXPayUploadVpFileResponse response = this.wxService.getWxMaXPayService().uploadVpFile(request, sigParams);
+    assertNotNull(response);
+  }
+
+  @Test
+  public void testGetUploadFileSign() throws Exception {
+    WxMaXPayGetUploadFileSignRequest request = WxMaXPayGetUploadFileSignRequest.builder()
+      .env(WxMaConstants.XPayEnv.PRODUCT)
+      .wxpayUrl("")
+      .complaintId("")
+      .convertCos(true)
+      .build();
+    WxMaXPaySigParams sigParams = new WxMaXPaySigParams();
+    sigParams.setAppKey("");
+    WxMaXPayGetUploadFileSignResponse response = this.wxService.getWxMaXPayService().getUploadFileSign(request, sigParams);
+    assertNotNull(response);
+  }
+
+  @Test
+  public void testDownloadAdverfundsOrder() throws Exception {
+    WxMaXPayDownloadAdverfundsOrderRequest request = WxMaXPayDownloadAdverfundsOrderRequest.builder()
+      .env(WxMaConstants.XPayEnv.PRODUCT)
+      .fundId("")
+      .build();
+    WxMaXPaySigParams sigParams = new WxMaXPaySigParams();
+    sigParams.setAppKey("123");
+    WxMaXPayDownloadAdverfundsOrderResponse response = this.wxService.getWxMaXPayService().downloadAdverfundsOrder(request, sigParams);
+    assertNotNull(response);
+  }
+
 }
diff --git a/weixin-java-mp/pom.xml b/weixin-java-mp/pom.xml
index 643f4f0d0e..691f86967e 100644
--- a/weixin-java-mp/pom.xml
+++ b/weixin-java-mp/pom.xml
@@ -7,7 +7,7 @@
   <parent>
     <groupId>com.github.binarywang</groupId>
     <artifactId>wx-java</artifactId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
 
   <artifactId>weixin-java-mp</artifactId>
@@ -31,6 +31,11 @@
       <artifactId>okhttp</artifactId>
       <scope>provided</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.httpcomponents.client5</groupId>
+      <artifactId>httpclient5</artifactId>
+      <scope>provided</scope>
+    </dependency>
 
     <dependency>
       <groupId>org.testng</groupId>
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMaterialService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMaterialService.java
index b3a6fb6a6c..ef396b7036 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMaterialService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMaterialService.java
@@ -146,30 +146,6 @@ public interface WxMpMaterialService {
      */
     WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMaterial material) throws WxErrorException;
 
-    /**
-     * <pre>
-     * 新增永久图文素材
-     *
-     * 详情请见: <a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1444738729&token=&lang=zh_CN">新增永久素材</a>
-     * 接口url格式：https://api.weixin.qq.com/cgi-bin/material/add_news?access_token=ACCESS_TOKEN
-     *
-     * 除了3天就会失效的临时素材外，开发者有时需要永久保存一些素材，届时就可以通过本接口新增永久素材。
-     * 永久图片素材新增后，将带有URL返回给开发者，开发者可以在腾讯系域名内使用（腾讯系域名外使用，图片将被屏蔽）。
-     * 请注意：
-     * 1、新增的永久素材也可以在公众平台官网素材管理模块中看到
-     * 2、永久素材的数量是有上限的，请谨慎新增。图文消息素材和图片素材的上限为5000，其他类型为1000
-     * 3、素材的格式大小等要求与公众平台官网一致。具体是，图片大小不超过2M，支持bmp/png/jpeg/jpg/gif格式，语音大小不超过5M，长度不超过60秒，支持mp3/wma/wav/amr格式
-     * 4、调用该接口需https协议
-     * </pre>
-     *
-     * @param news 上传的图文消息, 请看{@link WxMpMaterialNews}
-     * @return the wx mp material upload result
-     * @throws WxErrorException the wx error exception
-     * @deprecated 关于永久图文素材相关接口下线的公告 : https://mp.weixin.qq.com/cgi-bin/announce?action=getannouncement&announce_id=11644831863qFQSh&version=&token=2085564289&lang=zh_CN
-     */
-    @Deprecated
-  WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws WxErrorException;
-
     /**
      * <pre>
      * 获取声音或者图片永久素材
@@ -212,22 +188,6 @@ public interface WxMpMaterialService {
      */
     WxMpMaterialNews materialNewsInfo(String mediaId) throws WxErrorException;
 
-    /**
-     * <pre>
-     * 修改永久图文素材
-     *
-     * 详情请见: <a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1444738732&token=&lang=zh_CN">修改永久图文素材</a>
-     * 接口url格式：https://api.weixin.qq.com/cgi-bin/material/update_news?access_token=ACCESS_TOKEN
-     * </pre>
-     *
-     * @param wxMpMaterialArticleUpdate 用来更新图文素材的bean, 请看{@link WxMpMaterialArticleUpdate}
-     * @return the boolean
-     * @throws WxErrorException the wx error exception
-     * @deprecated 关于永久图文素材相关接口下线的公告 : https://mp.weixin.qq.com/cgi-bin/announce?action=getannouncement&announce_id=11644831863qFQSh&version=&token=2085564289&lang=zh_CN
-     */
-    @Deprecated
-  boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleUpdate) throws WxErrorException;
-
     /**
      * <pre>
      * 删除永久素材
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java
index ea8cab7e50..289cb6a067 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMemberCardService.java
@@ -2,9 +2,6 @@
 
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.mp.bean.card.CardUpdateResult;
-import me.chanjar.weixin.mp.bean.card.membercard.MemberCardActivateUserFormRequest;
-import me.chanjar.weixin.mp.bean.card.membercard.MemberCardActivateUserFormResult;
-import me.chanjar.weixin.mp.bean.card.membercard.MemberCardUpdateRequest;
 import me.chanjar.weixin.mp.bean.card.WxMpCardCreateResult;
 import me.chanjar.weixin.mp.bean.card.membercard.*;
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java
index 070e952c0f..f2a28c668c 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpMessageRouter.java
@@ -315,7 +315,7 @@ public WxMpXmlOutMessage route(String appid, final WxMpXmlMessage wxMessage) {
     return this.route(appid, wxMessage, new HashMap<>(2));
   }
 
-  private boolean isMsgDuplicated(WxMpXmlMessage wxMessage) {
+  protected boolean isMsgDuplicated(WxMpXmlMessage wxMessage) {
     StringBuilder messageId = new StringBuilder();
     if (wxMessage.getMsgId() == null) {
       messageId.append(wxMessage.getCreateTime())
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java
index 847f6e7ecf..ed8c5e6a79 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpQrcodeService.java
@@ -89,7 +89,7 @@ public interface WxMpQrcodeService {
      * @throws WxErrorException the wx error exception
      */
     @Deprecated
-  String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException;
+    String qrCodePictureUrl(String ticket, boolean needShortUrl) throws WxErrorException;
 
     /**
      * <pre>
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
index 6df78c12d2..47a24b7931 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
@@ -528,7 +528,7 @@ public interface WxMpService extends WxService {
    *
    * @return RequestHttp对象 request http
    */
-  RequestHttp getRequestHttp();
+  RequestHttp<?, ?> getRequestHttp();
 
   /**
    * 返回群发消息相关接口方法的实现类对象，以方便调用其各个接口.
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java
index 44ca69f3f3..0010932ca7 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpStoreService.java
@@ -11,11 +11,9 @@
  * 门店管理的相关接口代码.
  * Created by Binary Wang on 2016-09-23.
  *
- * @param <H> the type parameter
- * @param <P> the type parameter
  * @author <a href="https://github.com/binarywang">Binary Wang</a>
  */
-public interface WxMpStoreService<H, P> {
+public interface WxMpStoreService {
     /**
      * <pre>
      * 创建门店
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java
index b2719301ec..63ca608eba 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java
@@ -188,7 +188,7 @@ public boolean checkSignature(String timestamp, String nonce, String signature)
       return SHA1.gen(this.getWxMpConfigStorage().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;
     }
   }
@@ -649,7 +649,7 @@ public void setMaxRetryTimes(int maxRetryTimes) {
   }
 
   @Override
-  public RequestHttp getRequestHttp() {
+  public RequestHttp<H, P> getRequestHttp() {
     return this;
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java
index 2ac835bbc4..8fce1d4736 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpCardServiceImpl.java
@@ -114,7 +114,7 @@ public WxMpCardResult queryCardCode(String cardId, String code, boolean checkCon
     param.addProperty("code", code);
     param.addProperty("check_consume", checkConsume);
     String responseContent = this.wxMpService.post(WxMpApiUrl.Card.CARD_CODE_GET, param.toString());
-    JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
+    JsonElement tmpJsonElement = JsonParser.parseString(responseContent);
     return WxMpGsonBuilder.create().fromJson(tmpJsonElement,
       new TypeToken<WxMpCardResult>() {
       }.getType());
@@ -145,7 +145,7 @@ public void markCardCode(String code, String cardId, String openId, boolean isMa
     param.addProperty("openid", openId);
     param.addProperty("is_mark", isMark);
     String responseContent = this.getWxMpService().post(WxMpApiUrl.Card.CARD_CODE_MARK, param.toString());
-    JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
+    JsonElement tmpJsonElement = JsonParser.parseString(responseContent);
     WxMpCardResult cardResult = WxMpGsonBuilder.create().fromJson(tmpJsonElement,
       new TypeToken<WxMpCardResult>() {
       }.getType());
@@ -166,7 +166,7 @@ public String getCardDetail(String cardId) throws WxErrorException {
     if (!"0".equals(errcode)) {
       String errmsg = json.get("errmsg").getAsString();
       throw new WxErrorException(WxError.builder()
-        .errorCode(Integer.valueOf(errcode)).errorMsg(errmsg)
+        .errorCode(Integer.parseInt(errcode)).errorMsg(errmsg)
         .build());
     }
 
@@ -257,7 +257,7 @@ public WxMpCardDeleteResult deleteCard(String cardId) throws WxErrorException {
   @Override
   public WxMpCardCodeDepositResult cardCodeDeposit(String cardId, List<String> codeList) throws WxErrorException {
     checkCardId(cardId);
-    if (codeList.size() == 0 || codeList.size() > 100) {
+    if (codeList.isEmpty() || codeList.size() > 100) {
       throw new WxErrorException(WxError.builder().errorCode(40109).errorMsg("code数量为0或者code数量超过100个").build());
     }
     JsonObject param = new JsonObject();
@@ -283,7 +283,7 @@ public WxMpCardCodeDepositCountResult cardCodeDepositCount(String cardId) throws
   @Override
   public WxMpCardCodeCheckcodeResult cardCodeCheckcode(String cardId, List<String> codeList) throws WxErrorException {
     checkCardId(cardId);
-    if (codeList.size() == 0 || codeList.size() > 100) {
+    if (codeList.isEmpty() || codeList.size() > 100) {
       throw new WxErrorException(WxError.builder().errorCode(40109).errorMsg("code数量为0或者code数量超过100个").build());
     }
     JsonObject param = new JsonObject();
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideServiceImpl.java
index dd6256c3e8..94491a72f8 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideServiceImpl.java
@@ -121,7 +121,7 @@ public WxMpGuideConfig getGuideConfig(String account, String openid) throws WxEr
   @Override
   public void setGuideAcctConfig(boolean isDelete, List<String> blackKeyWord, String guideAutoReply) throws WxErrorException {
     JsonObject jsonObject1 = null;
-    if (blackKeyWord != null && blackKeyWord.size() > 0) {
+    if (blackKeyWord != null && !blackKeyWord.isEmpty()) {
       jsonObject1 = new JsonObject();
       JsonArray jsonArray = new JsonArray();
       blackKeyWord.forEach(jsonArray::add);
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideTagServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideTagServiceImpl.java
index 11b0e4d2de..4680bee320 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideTagServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpGuideTagServiceImpl.java
@@ -91,7 +91,7 @@ public List<String> getGuideBuyerTag(String account, String openid, String userO
       new TypeToken<List<String>>() {
       }.getType());
     if (isExclude) {
-      if (list.size() > 0) {
+      if (!list.isEmpty()) {
         if (list.get(list.size() - 1).contains("\n")) {
           list.remove(list.size() - 1);
         }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java
index cde4df5b67..24a88e3bff 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpKefuServiceImpl.java
@@ -144,7 +144,7 @@ public WxMpKfMsgList kfMsgList(Date startTime, Date endTime) throws WxErrorExcep
     if (result != null && result.getNumber() == number) {
       Long msgId = result.getMsgId();
       WxMpKfMsgList followingResult = this.kfMsgList(startTime, endTime, msgId, number);
-      while (followingResult != null && followingResult.getRecords().size() > 0) {
+      while (followingResult != null && !followingResult.getRecords().isEmpty()) {
         result.getRecords().addAll(followingResult.getRecords());
         result.setNumber(result.getNumber() + followingResult.getNumber());
         result.setMsgId(followingResult.getMsgId());
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java
index 45e1c5c4b1..dfaf7d8a98 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImpl.java
@@ -83,15 +83,6 @@ public WxMpMaterialUploadResult materialFileUpload(String mediaType, WxMpMateria
     return this.wxMpService.execute(MaterialUploadRequestExecutor.create(this.wxMpService.getRequestHttp()), url, material);
   }
 
-  @Override
-  public WxMpMaterialUploadResult materialNewsUpload(WxMpMaterialNews news) throws WxErrorException {
-    if (news == null || news.isEmpty()) {
-      throw new IllegalArgumentException("news is empty!");
-    }
-    String responseContent = this.wxMpService.post(NEWS_ADD_URL, news.toJson());
-    return WxMpMaterialUploadResult.fromJson(responseContent);
-  }
-
   @Override
   public InputStream materialImageOrVoiceDownload(String mediaId) throws WxErrorException {
     return this.wxMpService.execute(MaterialVoiceAndImageDownloadRequestExecutor
@@ -111,17 +102,6 @@ public WxMpMaterialNews materialNewsInfo(String mediaId) throws WxErrorException
       MATERIAL_GET_URL, mediaId);
   }
 
-  @Override
-  public boolean materialNewsUpdate(WxMpMaterialArticleUpdate wxMpMaterialArticleUpdate) throws WxErrorException {
-    String responseText = this.wxMpService.post(NEWS_UPDATE_URL, wxMpMaterialArticleUpdate.toJson());
-    WxError wxError = WxError.fromJson(responseText, WxType.MP);
-    if (wxError.getErrorCode() == 0) {
-      return true;
-    } else {
-      throw new WxErrorException(wxError);
-    }
-  }
-
   @Override
   public boolean materialDelete(String mediaId) throws WxErrorException {
     return this.wxMpService.execute(MaterialDeleteRequestExecutor.create(this.wxMpService.getRequestHttp()),
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java
index 4f4471b2bb..7a01c6a014 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java
@@ -24,11 +24,6 @@
 import me.chanjar.weixin.mp.bean.card.BaseInfo;
 import me.chanjar.weixin.mp.bean.card.CardUpdateResult;
 import me.chanjar.weixin.mp.bean.card.DateInfo;
-import me.chanjar.weixin.mp.bean.card.membercard.MemberCard;
-import me.chanjar.weixin.mp.bean.card.membercard.MemberCardActivateUserFormRequest;
-import me.chanjar.weixin.mp.bean.card.membercard.MemberCardActivateUserFormResult;
-import me.chanjar.weixin.mp.bean.card.membercard.MemberCardCreateRequest;
-import me.chanjar.weixin.mp.bean.card.membercard.MemberCardUpdateRequest;
 import me.chanjar.weixin.mp.bean.card.WxMpCardCreateResult;
 import me.chanjar.weixin.mp.bean.card.enums.BusinessServiceType;
 import me.chanjar.weixin.mp.bean.card.enums.CardColor;
@@ -222,7 +217,7 @@ public WxMpMemberCardUserInfoResult getUserInfo(String cardId, String code) thro
 
     String responseContent = this.getWxMpService().post(WxMpApiUrl.MemberCard.MEMBER_CARD_USER_INFO_GET, jsonObject.toString());
     log.debug("{}", responseContent);
-    JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
+    JsonElement tmpJsonElement = JsonParser.parseString(responseContent);
     return WxMpGsonBuilder.create().fromJson(tmpJsonElement,
       new TypeToken<WxMpMemberCardUserInfoResult>() {
       }.getType());
@@ -234,7 +229,7 @@ public WxMpMemberCardUpdateResult updateUserMemberCard(WxMpMemberCardUpdateMessa
 
     String responseContent = this.getWxMpService().post(WxMpApiUrl.MemberCard.MEMBER_CARD_UPDATE_USER, GSON.toJson(updateUserMessage));
 
-    JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
+    JsonElement tmpJsonElement = JsonParser.parseString(responseContent);
     return WxMpGsonBuilder.create().fromJson(tmpJsonElement,
       new TypeToken<WxMpMemberCardUpdateResult>() {
       }.getType());
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMerchantInvoiceServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMerchantInvoiceServiceImpl.java
index 4631a2e2cc..361c0f52d1 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMerchantInvoiceServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMerchantInvoiceServiceImpl.java
@@ -12,7 +12,6 @@
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.bean.invoice.merchant.*;
 import me.chanjar.weixin.mp.enums.WxMpApiUrl;
-import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 
 import java.util.Map;
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java
index 7bad648cb5..5719f4bb46 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpQrcodeServiceImpl.java
@@ -2,7 +2,6 @@
 
 import com.google.gson.JsonObject;
 import lombok.RequiredArgsConstructor;
-import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.mp.api.WxMpQrcodeService;
 import me.chanjar.weixin.mp.api.WxMpService;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java
index 750f787137..c61fd09b9f 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpClientImpl.java
@@ -1,18 +1,17 @@
 package me.chanjar.weixin.mp.api.impl;
 
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
+import me.chanjar.weixin.common.util.http.apache.ApacheBasicResponseHandler;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
 import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
 import me.chanjar.weixin.mp.bean.WxMpStableAccessTokenRequest;
 import me.chanjar.weixin.mp.config.WxMpConfigStorage;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.ContentType;
 import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.BasicResponseHandler;
 import org.apache.http.impl.client.CloseableHttpClient;
 
 import java.io.IOException;
@@ -40,8 +39,8 @@ public HttpHost getRequestHttpProxy() {
   }
 
   @Override
-  public HttpType getRequestType() {
-    return HttpType.APACHE_HTTP;
+  public HttpClientType getRequestType() {
+    return HttpClientType.APACHE_HTTP;
   }
 
   @Override
@@ -68,61 +67,31 @@ public void initHttp() {
   protected String doGetAccessTokenRequest() throws IOException {
     String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(getWxMpConfigStorage()), getWxMpConfigStorage().getAppId(), getWxMpConfigStorage().getSecret());
 
-    HttpGet httpGet = null;
-    CloseableHttpResponse response = null;
-    try {
-      httpGet = new HttpGet(url);
-      if (this.getRequestHttpProxy() != null) {
-        RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
-        httpGet.setConfig(config);
-      }
-      response = getRequestHttpClient().execute(httpGet);
-      return new BasicResponseHandler().handleResponse(response);
-    } finally {
-      if (httpGet != null) {
-        httpGet.releaseConnection();
-      }
-      if (response != null) {
-        try {
-          response.close();
-        } catch (IOException e) {
-        }
-      }
+    HttpGet httpGet = new HttpGet(url);
+    if (this.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
+      httpGet.setConfig(config);
     }
+    return getRequestHttpClient().execute(httpGet, ApacheBasicResponseHandler.INSTANCE);
   }
 
   @Override
   protected String doGetStableAccessTokenRequest(boolean forceRefresh) throws IOException {
     String url = GET_STABLE_ACCESS_TOKEN_URL.getUrl(getWxMpConfigStorage());
 
-    HttpPost httpPost = null;
-    CloseableHttpResponse response = null;
-    try {
-      httpPost = new HttpPost(url);
-      if (this.getRequestHttpProxy() != null) {
-        RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
-        httpPost.setConfig(config);
-      }
-      WxMpStableAccessTokenRequest wxMaAccessTokenRequest = new WxMpStableAccessTokenRequest();
-      wxMaAccessTokenRequest.setAppid(this.getWxMpConfigStorage().getAppId());
-      wxMaAccessTokenRequest.setSecret(this.getWxMpConfigStorage().getSecret());
-      wxMaAccessTokenRequest.setGrantType("client_credential");
-      wxMaAccessTokenRequest.setForceRefresh(forceRefresh);
-
-      httpPost.setEntity(new StringEntity(wxMaAccessTokenRequest.toJson(), ContentType.APPLICATION_JSON));
-      response = getRequestHttpClient().execute(httpPost);
-      return new BasicResponseHandler().handleResponse(response);
-    } finally {
-      if (httpPost != null) {
-        httpPost.releaseConnection();
-      }
-      if (response != null) {
-        try {
-          response.close();
-        } catch (IOException e) {
-        }
-      }
+    HttpPost httpPost = new HttpPost(url);
+    if (this.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
     }
+    WxMpStableAccessTokenRequest wxMaAccessTokenRequest = new WxMpStableAccessTokenRequest();
+    wxMaAccessTokenRequest.setAppid(this.getWxMpConfigStorage().getAppId());
+    wxMaAccessTokenRequest.setSecret(this.getWxMpConfigStorage().getSecret());
+    wxMaAccessTokenRequest.setGrantType("client_credential");
+    wxMaAccessTokenRequest.setForceRefresh(forceRefresh);
+
+    httpPost.setEntity(new StringEntity(wxMaAccessTokenRequest.toJson(), ContentType.APPLICATION_JSON));
+    return getRequestHttpClient().execute(httpPost, ApacheBasicResponseHandler.INSTANCE);
   }
 
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpComponentsImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpComponentsImpl.java
new file mode 100644
index 0000000000..bbf065acfc
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceHttpComponentsImpl.java
@@ -0,0 +1,94 @@
+package me.chanjar.weixin.mp.api.impl;
+
+import me.chanjar.weixin.common.util.http.HttpClientType;
+import me.chanjar.weixin.common.util.http.hc.BasicResponseHandler;
+import me.chanjar.weixin.common.util.http.hc.DefaultHttpComponentsClientBuilder;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsClientBuilder;
+import me.chanjar.weixin.mp.bean.WxMpStableAccessTokenRequest;
+import me.chanjar.weixin.mp.config.WxMpConfigStorage;
+import org.apache.hc.client5.http.classic.methods.HttpGet;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+
+import java.io.IOException;
+
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GET_ACCESS_TOKEN_URL;
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GET_STABLE_ACCESS_TOKEN_URL;
+
+/**
+ * apache http client方式实现.
+ *
+ * @author altusea
+ */
+public class WxMpServiceHttpComponentsImpl extends BaseWxMpServiceImpl<CloseableHttpClient, HttpHost> {
+  private CloseableHttpClient httpClient;
+  private HttpHost httpProxy;
+
+  @Override
+  public CloseableHttpClient getRequestHttpClient() {
+    return httpClient;
+  }
+
+  @Override
+  public HttpHost getRequestHttpProxy() {
+    return httpProxy;
+  }
+
+  @Override
+  public HttpClientType getRequestType() {
+    return HttpClientType.HTTP_COMPONENTS;
+  }
+
+  @Override
+  public void initHttp() {
+    WxMpConfigStorage configStorage = this.getWxMpConfigStorage();
+    HttpComponentsClientBuilder apacheHttpClientBuilder = DefaultHttpComponentsClientBuilder.get();
+
+    apacheHttpClientBuilder.httpProxyHost(configStorage.getHttpProxyHost())
+      .httpProxyPort(configStorage.getHttpProxyPort())
+      .httpProxyUsername(configStorage.getHttpProxyUsername())
+      .httpProxyPassword(configStorage.getHttpProxyPassword().toCharArray());
+
+    if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) {
+      this.httpProxy = new HttpHost(configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort());
+    }
+
+    this.httpClient = apacheHttpClientBuilder.build();
+  }
+
+  @Override
+  protected String doGetAccessTokenRequest() throws IOException {
+    String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(getWxMpConfigStorage()), getWxMpConfigStorage().getAppId(), getWxMpConfigStorage().getSecret());
+
+    HttpGet httpGet = new HttpGet(url);
+    if (this.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
+      httpGet.setConfig(config);
+    }
+    return getRequestHttpClient().execute(httpGet, BasicResponseHandler.INSTANCE);
+  }
+
+  @Override
+  protected String doGetStableAccessTokenRequest(boolean forceRefresh) throws IOException {
+    String url = GET_STABLE_ACCESS_TOKEN_URL.getUrl(getWxMpConfigStorage());
+
+    HttpPost httpPost = new HttpPost(url);
+    if (this.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+    WxMpStableAccessTokenRequest wxMaAccessTokenRequest = new WxMpStableAccessTokenRequest();
+    wxMaAccessTokenRequest.setAppid(this.getWxMpConfigStorage().getAppId());
+    wxMaAccessTokenRequest.setSecret(this.getWxMpConfigStorage().getSecret());
+    wxMaAccessTokenRequest.setGrantType("client_credential");
+    wxMaAccessTokenRequest.setForceRefresh(forceRefresh);
+
+    httpPost.setEntity(new StringEntity(wxMaAccessTokenRequest.toJson(), ContentType.APPLICATION_JSON));
+    return getRequestHttpClient().execute(httpPost, BasicResponseHandler.INSTANCE);
+  }
+
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java
index b174c4bdf9..7f67b3478b 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceJoddHttpImpl.java
@@ -5,7 +5,7 @@
 import jodd.http.ProxyInfo;
 import jodd.http.net.SocketHttpConnectionProvider;
 import jodd.net.MimeTypes;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
 import me.chanjar.weixin.mp.bean.WxMpStableAccessTokenRequest;
 import me.chanjar.weixin.mp.config.WxMpConfigStorage;
 
@@ -35,8 +35,8 @@ public ProxyInfo getRequestHttpProxy() {
   }
 
   @Override
-  public HttpType getRequestType() {
-    return HttpType.JODD_HTTP;
+  public HttpClientType getRequestType() {
+    return HttpClientType.JODD_HTTP;
   }
 
   @Override
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java
index 6d4869b6a1..8bd4b2a227 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpServiceOkHttpImpl.java
@@ -1,6 +1,6 @@
 package me.chanjar.weixin.mp.api.impl;
 
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
 import me.chanjar.weixin.common.util.http.okhttp.DefaultOkHttpClientBuilder;
 import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
 import me.chanjar.weixin.mp.bean.WxMpStableAccessTokenRequest;
@@ -33,8 +33,8 @@ public OkHttpProxyInfo getRequestHttpProxy() {
   }
 
   @Override
-  public HttpType getRequestType() {
-    return HttpType.OK_HTTP;
+  public HttpClientType getRequestType() {
+    return HttpClientType.OK_HTTP;
   }
 
   @Override
@@ -50,12 +50,12 @@ public void initHttp() {
       clientBuilder.proxy(getRequestHttpProxy().getProxy());
 
       //设置授权
-      clientBuilder.authenticator(new Authenticator() {
+      clientBuilder.proxyAuthenticator(new Authenticator() {
         @Override
         public Request authenticate(Route route, Response response) throws IOException {
           String credential = Credentials.basic(httpProxy.getProxyUsername(), httpProxy.getProxyPassword());
           return response.request().newBuilder()
-            .header("Authorization", credential)
+            .header("Proxy-Authorization", credential)
             .build();
         }
       });
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImpl.java
index e1378efc5c..a71a753ecd 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpStoreServiceImpl.java
@@ -86,7 +86,7 @@ public List<WxMpStoreInfo> listAll() throws WxErrorException {
     if (list.getTotalCount() > limit) {
       int begin = limit;
       WxMpStoreListResult followingList = this.list(begin, limit);
-      while (followingList.getBusinessList().size() > 0) {
+      while (!followingList.getBusinessList().isEmpty()) {
         stores.addAll(followingList.getBusinessList());
         begin += limit;
         if (begin >= list.getTotalCount()) {
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java
index 0b75bb996b..2eca3fccea 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpWifiServiceImpl.java
@@ -46,11 +46,7 @@ public boolean updateShopWifiInfo(int shopId, String oldSsid, String ssid, Strin
     if (password != null) {
       json.addProperty("password", password);
     }
-    try {
-      this.wxMpService.post(BIZWIFI_SHOP_UPDATE, json.toString());
-      return true;
-    } catch (WxErrorException e) {
-      throw e;
-    }
+    this.wxMpService.post(BIZWIFI_SHOP_UPDATE, json.toString());
+    return true;
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeInfoResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeInfoResult.java
index 4cd6430000..3c053480dd 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeInfoResult.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/WxMpShakeInfoResult.java
@@ -26,7 +26,7 @@ public static WxMpShakeInfoResult fromJson(String json) {
   }
 
   @Data
-  public class ShakeInfoData implements Serializable {
+  public static class ShakeInfoData implements Serializable {
     private static final long serialVersionUID = -4828142206067489488L;
 
     private String page_id;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/BusinessServiceType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/BusinessServiceType.java
index 3ae9cf8937..999cac43ce 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/BusinessServiceType.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/BusinessServiceType.java
@@ -9,7 +9,7 @@ public enum BusinessServiceType {
   BIZ_SERVICE_WITH_PET("可带宠物"),
   BIZ_SERVICE_FREE_WIFI("可带宠物");
 
-  private String description;
+  private final String description;
 
   BusinessServiceType(String description) {
     this.description = description;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardCodeType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardCodeType.java
index 35263188e0..61fb137701 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardCodeType.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardCodeType.java
@@ -9,7 +9,7 @@ public enum CardCodeType {
   CODE_TYPE_BARCODE("一维码"),
   CODE_TYPE_QRCODE("二维码");
 
-  private String description;
+  private final String description;
 
   CardCodeType(String description) {
     this.description = description;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardColor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardColor.java
index a694d4d372..594a78b58b 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardColor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardColor.java
@@ -22,7 +22,7 @@ public enum CardColor {
   Color101("#cf3e36"),
   Color102("#5E6671");
 
-  private String type;
+  private final String type;
 
   CardColor(String type) {
     this.type = type;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardFieldType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardFieldType.java
index 42804b635b..e4f69d42a4 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardFieldType.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardFieldType.java
@@ -11,7 +11,7 @@ public enum CardFieldType {
   CUSTOM_FIELD("自定义选项"),
   RICH_FIELD("自定义富文本类型");
 
-  private String description;
+  private final String description;
 
   CardFieldType(String description) {
     this.description = description;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardRichFieldType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardRichFieldType.java
index 7659864939..eac1625d6c 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardRichFieldType.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardRichFieldType.java
@@ -11,7 +11,7 @@ public enum CardRichFieldType {
   FORM_FIELD_SELECT("自定义选择项"),
   FORM_FIELD_CHECK_BOX("自定义多选");
 
-  private String description;
+  private final String description;
 
   CardRichFieldType(String description) {
     this.description = description;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardSceneType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardSceneType.java
index ec5b9fcfbc..429dcacdea 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardSceneType.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardSceneType.java
@@ -9,7 +9,7 @@ public enum CardSceneType {
   SCENE_IVR("自动回复"),
   SCENE_CARD_CUSTOM_CELL("卡券自定义cell");
 
-  private String description;
+  private final String description;
 
   CardSceneType(String description) {
     this.description = description;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardStatusType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardStatusType.java
index 4108b7d4c2..bcb414aa6c 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardStatusType.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardStatusType.java
@@ -7,7 +7,7 @@ public enum CardStatusType {
   CARD_STATUS_DELETE("卡券被商户删除"),
   CARD_STATUS_DISPATCH("在公众平台投放过的卡券");
 
-  private String description;
+  private final String description;
 
   CardStatusType(String description) {
     this.description = description;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardWechatFieldType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardWechatFieldType.java
index c34bd58ace..9dc7f5d427 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardWechatFieldType.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CardWechatFieldType.java
@@ -23,7 +23,7 @@ public enum CardWechatFieldType {
   USER_FORM_INFO_FLAG_INCOME("收入"),
   USER_FORM_INFO_FLAG_HABIT("兴趣爱好");
 
-  private String description;
+  private final String description;
 
   CardWechatFieldType(String description) {
     this.description = description;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CustomFieldNameType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CustomFieldNameType.java
index 53f3df8cf9..e6bea61685 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CustomFieldNameType.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/CustomFieldNameType.java
@@ -14,7 +14,7 @@ public enum CustomFieldNameType {
   FIELD_NAME_TYPE_SET_POINTS("集点"),
   FIELD_NAME_TYPE_TIMS("次数");
 
-  private String description;
+  private final String description;
 
   CustomFieldNameType(String description) {
     this.description = description;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/DateInfoType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/DateInfoType.java
index bd8a23551c..93893dfa12 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/DateInfoType.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/card/enums/DateInfoType.java
@@ -5,7 +5,7 @@ public enum DateInfoType {
   DATE_TYPE_FIX_TIME_RANGE("固定日期"),
   DATE_TYPE_FIX_TERM("固定时长");
 
-  private String description;
+  private final String description;
 
   DateInfoType(String description) {
     this.description = description;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/BaseResp.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/BaseResp.java
index a0b65c8842..128e2d2528 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/BaseResp.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/device/BaseResp.java
@@ -21,7 +21,7 @@ public class BaseResp extends AbstractDeviceBean {
   private String errMsg;
 
   @Data
-  private class BaseInfo {
+  private static class BaseInfo {
     @SerializedName("device_type")
     private String deviceType;
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftArticles.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftArticles.java
index 80a7d37d4b..db37c66d10 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftArticles.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftArticles.java
@@ -23,6 +23,13 @@
 @NoArgsConstructor
 @AllArgsConstructor
 public class WxMpDraftArticles implements ToJson, Serializable {
+  /**
+   * 文章类型，分别有图文消息（news）、图片消息（newspic），不填默认为图文消息（news）
+   *
+   * @see me.chanjar.weixin.common.api.WxConsts.ArticleType
+   */
+  @SerializedName("article_type")
+  private String articleType;
   /**
    * 标题
    */
@@ -78,18 +85,31 @@ public class WxMpDraftArticles implements ToJson, Serializable {
    */
   @SerializedName("thumb_url")
   private String thumbUrl;
-
   /**
    * 封面裁剪为2.35:1规格的坐标字段。以原始图片（thumb_media_id）左上角（0,0），右下角（1,1）建立平面坐标系，经过裁剪后的图片，其左上角所在的坐标即为（X1,Y1）,右下角所在的坐标则为（X2,Y2），用分隔符_拼接为X1_Y1_X2_Y2，每个坐标值的精度为不超过小数点后6位数字。示例见下图，图中(X1,Y1) 等于（0.1945,0）,(X2,Y2)等于（1,0.5236），所以请求参数值为0.1945_0_1_0.5236。
    */
   @SerializedName("pic_crop_235_1")
   private String picCrop2351;
-
   /**
    * 封面裁剪为1:1规格的坐标字段，裁剪原理同pic_crop_235_1，裁剪后的图片必须符合规格要求。
    */
   @SerializedName("pic_crop_1_1")
   private String picCrop11;
+  /**
+   * 图片消息里的图片相关信息，图片数量最多为20张，首张图片即为封面图
+   */
+  @SerializedName("image_info")
+  private WxMpDraftImageInfo imageInfo;
+  /**
+   * 封面图裁剪信息
+   */
+  @SerializedName("cover_info")
+  private WxMpDraftCoverInfo coverInfo;
+  /**
+   * 商品相关信息
+   */
+  @SerializedName("product_info")
+  private WxMpDraftProductInfo productInfo;
 
   public static WxMpDraftArticles fromJson(String json) {
     return WxGsonBuilder.create().fromJson(json, WxMpDraftArticles.class);
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftCoverInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftCoverInfo.java
new file mode 100644
index 0000000000..9b2ba09325
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftCoverInfo.java
@@ -0,0 +1,53 @@
+package me.chanjar.weixin.mp.bean.draft;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 草稿箱能力-图片消息里的封面裁剪信息
+ *
+ * @author 阿杆
+ * created on 2025/5/23
+ */
+@Data
+@Builder
+@Accessors(chain = true)
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMpDraftCoverInfo implements Serializable {
+
+  private static final long serialVersionUID = -1676442833397632638L;
+
+  /**
+   * 封面裁剪信息，裁剪比例ratio支持：“1_1”，“16_9”,“2.35_1”。
+   * 以图片左上角（0,0），右下角（1,1）建立平面坐标系，经过裁剪后的图片，其左上角所在的坐标填入x1，y1参数，右下角所在的坐标填入x2，y2参数
+   */
+  @SerializedName("crop_percent_list")
+  private List<CropPercent> cropPercentList;
+
+  public static WxMpDraftCoverInfo fromJson(String json) {
+    return WxGsonBuilder.create().fromJson(json, WxMpDraftCoverInfo.class);
+  }
+
+  @Data
+  @Builder
+  @NoArgsConstructor
+  @AllArgsConstructor
+  public static class CropPercent implements Serializable {
+    private static final long serialVersionUID = 8495528870408737871L;
+    private String ratio;
+    private String x1;
+    private String y1;
+    private String x2;
+    private String y2;
+  }
+
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftImageInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftImageInfo.java
new file mode 100644
index 0000000000..0f2af9f45b
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftImageInfo.java
@@ -0,0 +1,51 @@
+package me.chanjar.weixin.mp.bean.draft;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 草稿箱能力-图片消息里的图片相关信息
+ *
+ * @author 阿杆
+ * created on 2025/5/23
+ */
+@Data
+@Builder
+@Accessors(chain = true)
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMpDraftImageInfo implements Serializable {
+
+  private static final long serialVersionUID = -1997245511033770476L;
+
+  /**
+   * 图片列表
+   */
+  @SerializedName("image_list")
+  private List<ImageItem> imageList;
+
+  public static WxMpDraftImageInfo fromJson(String json) {
+    return WxGsonBuilder.create().fromJson(json, WxMpDraftImageInfo.class);
+  }
+
+  @Data
+  @NoArgsConstructor
+  @AllArgsConstructor
+  public static class ImageItem implements Serializable {
+    private static final long serialVersionUID = 4180558781166966752L;
+    /**
+     * 图片消息里的图片素材id（必须是永久MediaID）
+     */
+    @SerializedName("image_media_id")
+    private String imageMediaId;
+  }
+
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftProductInfo.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftProductInfo.java
new file mode 100644
index 0000000000..1d6016d7a1
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/draft/WxMpDraftProductInfo.java
@@ -0,0 +1,48 @@
+package me.chanjar.weixin.mp.bean.draft;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
+
+import java.io.Serializable;
+
+/**
+ * 草稿箱能力-商品相关信息
+ *
+ * @author 阿杆
+ * created on 2025/5/23
+ */
+@Data
+@Builder
+@Accessors(chain = true)
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxMpDraftProductInfo implements Serializable {
+  private static final long serialVersionUID = 8637785998127610863L;
+
+  /**
+   * 文末插入商品相关信息
+   */
+  @SerializedName("footer_product_info")
+  private FooterProductInfo footerProductInfo;
+
+  public static WxMpDraftProductInfo fromJson(String json) {
+    return WxGsonBuilder.create().fromJson(json, WxMpDraftProductInfo.class);
+  }
+
+  @Data
+  @NoArgsConstructor
+  @AllArgsConstructor
+  public static class FooterProductInfo {
+    /**
+     * 商品key
+     */
+    @SerializedName("product_key")
+    private String productKey;
+  }
+
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java
index 27b7eaecc7..3d5f4ac3a0 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java
@@ -186,6 +186,22 @@ public class WxMpXmlMessage implements Serializable {
   @JacksonXmlCData
   private String unionId;
 
+  @XStreamAlias("ret")
+  @JacksonXmlProperty(localName = "ret")
+  private Integer ret;
+  
+  @XStreamAlias("nickname")
+  @JacksonXmlProperty(localName = "nickname")
+  private String nickname;
+
+  @XStreamAlias("first")
+  @JacksonXmlProperty(localName = "first")
+  private String first;
+  
+  @XStreamAlias("second")
+  @JacksonXmlProperty(localName = "second")
+  private String second;
+
   ///////////////////////////////////////
   // 群发消息返回的结果
   ///////////////////////////////////////
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/subscribe/WxMpSubscribeMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/subscribe/WxMpSubscribeMessage.java
index d2695959e8..6820d103b8 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/subscribe/WxMpSubscribeMessage.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/subscribe/WxMpSubscribeMessage.java
@@ -17,7 +17,7 @@
 @NoArgsConstructor
 @Builder
 @AllArgsConstructor
-public class WxMpSubscribeMessage {
+public class WxMpSubscribeMessage implements Serializable {
 
   /**
    * 接收者openid.
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateMessage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateMessage.java
index a04d8bb896..02211937f9 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateMessage.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateMessage.java
@@ -1,20 +1,16 @@
 package me.chanjar.weixin.mp.bean.template;
 
+import lombok.*;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
+import org.apache.commons.lang3.StringUtils;
+
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
-import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
-
 /**
  * 模板消息.
- * 参考 http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277&token=&lang=zh_CN 发送模板消息接口部分
+ * 参考 <a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277&token=&lang=zh_CN">发送模板消息接口部分</a>
  *
  * @author <a href="https://github.com/binarywang">Binary Wang</a>
  */
@@ -67,10 +63,35 @@ public WxMpTemplateMessage addData(WxMpTemplateData datum) {
     if (this.data == null) {
       this.data = new ArrayList<>();
     }
-    this.data.add(datum);
+    this.data.add(resetValue(datum));
     return this;
   }
 
+  /**
+   * 处理微信模版消息字符串长度问题
+   *
+   * @link <a href=https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Template_Message_Interface.html#%E7%B1%BB%E7%9B%AE%E6%A8%A1%E6%9D%BF%E6%B6%88%E6%81%AF">模板消息</a>
+   */
+  private WxMpTemplateData resetValue(WxMpTemplateData datum) {
+    String name = datum.getName();
+    String value = datum.getValue();
+
+    if (StringUtils.startsWith(name, "thing") && value.length() > 20) {
+      value = StringUtils.substring(value, 0, 17) + "...";
+    } else if (StringUtils.startsWith(name, "character_string") && value.length() > 32) {
+      value = StringUtils.substring(value, 0, 29) + "...";
+    } else if (StringUtils.startsWith(name, "phone_number") && value.length() > 17) {
+      value = StringUtils.substring(value, 0, 14) + "...";
+    } else if (StringUtils.startsWith(name, "car_number") && value.length() > 8) {
+      value = StringUtils.substring(value, 0, 5) + "...";
+    } else if (StringUtils.startsWith(name, "const") && value.length() > 20) {
+      value = StringUtils.substring(value, 0, 17) + "...";
+    }
+
+    datum.setValue(value);
+    return datum;
+  }
+
   public String toJson() {
     return WxMpGsonBuilder.create().toJson(this);
   }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/WxMpConfigStorage.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/WxMpConfigStorage.java
index 148ad6ebef..11aeef6124 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/WxMpConfigStorage.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/WxMpConfigStorage.java
@@ -22,13 +22,15 @@ public interface WxMpConfigStorage {
 
   /**
    * Is use stable access token api
-   * @Link https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/getStableAccessToken.html
+   *
    * @return the boolean
+   * @link https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/getStableAccessToken.html
    */
   boolean isStableAccessToken();
 
   /**
    * Set use stable access token api
+   *
    * @param useStableAccessToken true is use, false is not
    */
   void useStableAccessToken(boolean useStableAccessToken);
@@ -154,9 +156,28 @@ public interface WxMpConfigStorage {
    * Gets oauth 2 redirect uri.
    *
    * @return the oauth 2 redirect uri
+   * @deprecated This method is deprecated due to incorrect naming convention.
+   * Use {@link #getOauth2RedirectUrl()} instead.
    */
+  @Deprecated
   String getOauth2redirectUri();
 
+  /**
+   * Gets OAuth 2.0 redirect Url
+   *
+   * @return the OAuth 2.0 redirect Url
+   * @author <a href="https://gitee.com/pengles">Peng Les</a>
+   */
+  String getOauth2RedirectUrl();
+
+  /**
+   * Gets QR connect redirect Url
+   *
+   * @return the QR connect redirect Url
+   * @author <a href="https://gitee.com/pengles">Peng Les</a>
+   */
+  String getQrConnectRedirectUrl();
+
   /**
    * Gets http proxy host.
    *
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/impl/WxMpDefaultConfigImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/impl/WxMpDefaultConfigImpl.java
index 8c0ccfe666..da47fc49fa 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/impl/WxMpDefaultConfigImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/impl/WxMpDefaultConfigImpl.java
@@ -34,7 +34,10 @@ public class WxMpDefaultConfigImpl implements WxMpConfigStorage, Serializable {
   protected volatile String aesKey;
   protected volatile long expiresTime;
 
+  @Deprecated
   protected volatile String oauth2redirectUri;
+  protected volatile String oauth2RedirectUrl;
+  protected volatile String qrConnectRedirectUrl;
 
   protected volatile String httpProxyHost;
   protected volatile int httpProxyPort;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/impl/WxMpMapConfigImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/impl/WxMpMapConfigImpl.java
index cd701d1efc..72e6e615f7 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/impl/WxMpMapConfigImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/config/impl/WxMpMapConfigImpl.java
@@ -15,7 +15,7 @@ public class WxMpMapConfigImpl extends WxMpDefaultConfigImpl {
 
   private static final long serialVersionUID = 5311395137835650104L;
 
-  private static final ConcurrentHashMap<String, String> CONCURRENT_HASH_MAP = new ConcurrentHashMap<>(1);
+  private final ConcurrentHashMap<String, String> CONCURRENT_HASH_MAP = new ConcurrentHashMap<>(1);
 
   private static final String MAP_KEY = "access_token";
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/AiLangType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/AiLangType.java
index b37772b01a..5049e88565 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/AiLangType.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/AiLangType.java
@@ -21,7 +21,7 @@ public enum AiLangType {
    */
   en_US("en_US");
 
-  private String code;
+  private final String code;
 
   AiLangType(String code) {
     this.code = code;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxCardType.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxCardType.java
index 568f3cdedb..bb360eba3a 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxCardType.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxCardType.java
@@ -14,7 +14,7 @@ public enum WxCardType {
   GIFT("GIFT"),
   GENERAL_COUPON("GENERAL_COUPON");
 
-  private String code;
+  private final String code;
 
   WxCardType(String code) {
     this.code = code;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/WxMpConfigStorageHolder.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/WxMpConfigStorageHolder.java
index b5e0dd8847..1a2f7a9d3c 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/WxMpConfigStorageHolder.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/WxMpConfigStorageHolder.java
@@ -5,12 +5,7 @@
  * created on  2019-03-20 22:06
  */
 public class WxMpConfigStorageHolder {
-  private static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<String>() {
-    @Override
-    protected String initialValue() {
-      return "default";
-    }
-  };
+  private static final ThreadLocal<String> THREAD_LOCAL = ThreadLocal.withInitial(() -> "default");
 
   public static String get() {
     return THREAD_LOCAL.get();
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java
index b14023ef91..99d759f32f 100755
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/crypto/WxMpCryptUtil.java
@@ -17,8 +17,6 @@
  */
 package me.chanjar.weixin.mp.util.crypto;
 
-import com.google.common.base.CharMatcher;
-import com.google.common.io.BaseEncoding;
 import me.chanjar.weixin.mp.config.WxMpConfigStorage;
 import org.apache.commons.lang3.StringUtils;
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteApacheHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteApacheHttpRequestExecutor.java
index 72fcaf1b3f..3d5cc58e7a 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteApacheHttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteApacheHttpRequestExecutor.java
@@ -8,7 +8,6 @@
 import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.impl.client.CloseableHttpClient;
@@ -21,7 +20,7 @@
  * Created by ecoolper on 2017/5/5.
  */
 public class MaterialDeleteApacheHttpRequestExecutor extends MaterialDeleteRequestExecutor<CloseableHttpClient, HttpHost> {
-  public MaterialDeleteApacheHttpRequestExecutor(RequestHttp requestHttp) {
+  public MaterialDeleteApacheHttpRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
     super(requestHttp);
   }
 
@@ -36,16 +35,11 @@ public Boolean execute(String uri, String materialId, WxType wxType) throws WxEr
     Map<String, String> params = new HashMap<>();
     params.put("media_id", materialId);
     httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params)));
-    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
-      String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
-      WxError error = WxError.fromJson(responseContent, WxType.MP);
-      if (error.getErrorCode() != 0) {
-        throw new WxErrorException(error);
-      } else {
-        return true;
-      }
-    } finally {
-      httpPost.releaseConnection();
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, WxType.MP);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
     }
+    return true;
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteHttpComponentsRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteHttpComponentsRequestExecutor.java
new file mode 100644
index 0000000000..46f8f16988
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteHttpComponentsRequestExecutor.java
@@ -0,0 +1,42 @@
+package me.chanjar.weixin.mp.util.requestexecuter.material;
+
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MaterialDeleteHttpComponentsRequestExecutor extends MaterialDeleteRequestExecutor<CloseableHttpClient, HttpHost> {
+  public MaterialDeleteHttpComponentsRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
+
+  @Override
+  public Boolean execute(String uri, String materialId, WxType wxType) throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+
+    Map<String, String> params = new HashMap<>();
+    params.put("media_id", materialId);
+    httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params)));
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, WxType.MP);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
+    }
+    return true;
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteJoddHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteJoddHttpRequestExecutor.java
index 318299bb34..5e8d5ee8f5 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteJoddHttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteJoddHttpRequestExecutor.java
@@ -4,7 +4,6 @@
 import jodd.http.HttpRequest;
 import jodd.http.HttpResponse;
 import jodd.http.ProxyInfo;
-import jodd.util.StringPool;
 
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
@@ -18,7 +17,7 @@
  * Created by ecoolper on 2017/5/5.
  */
 public class MaterialDeleteJoddHttpRequestExecutor extends MaterialDeleteRequestExecutor<HttpConnectionProvider, ProxyInfo> {
-  public MaterialDeleteJoddHttpRequestExecutor(RequestHttp requestHttp) {
+  public MaterialDeleteJoddHttpRequestExecutor(RequestHttp<HttpConnectionProvider, ProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteOkhttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteOkhttpRequestExecutor.java
index ed9aaa8a84..7ad3ebb6fd 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteOkhttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteOkhttpRequestExecutor.java
@@ -23,7 +23,7 @@
 public class MaterialDeleteOkhttpRequestExecutor extends MaterialDeleteRequestExecutor<OkHttpClient, OkHttpProxyInfo> {
   private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
-  public MaterialDeleteOkhttpRequestExecutor(RequestHttp requestHttp) {
+  public MaterialDeleteOkhttpRequestExecutor(RequestHttp<OkHttpClient, OkHttpProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteRequestExecutor.java
index 18e696938b..a6dea564e2 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialDeleteRequestExecutor.java
@@ -1,17 +1,21 @@
 package me.chanjar.weixin.mp.util.requestexecuter.material;
 
-import java.io.IOException;
-
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.ResponseHandler;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import okhttp3.OkHttpClient;
+
+import java.io.IOException;
 
 public abstract class MaterialDeleteRequestExecutor<H, P> implements RequestExecutor<Boolean, String> {
   protected RequestHttp<H, P> requestHttp;
 
-  public MaterialDeleteRequestExecutor(RequestHttp requestHttp) {
+  public MaterialDeleteRequestExecutor(RequestHttp<H, P> requestHttp) {
     this.requestHttp = requestHttp;
   }
 
@@ -20,16 +24,21 @@ public void execute(String uri, String data, ResponseHandler<Boolean> handler, W
     handler.handle(this.execute(uri, data, wxType));
   }
 
-  public static RequestExecutor<Boolean, String> create(RequestHttp requestHttp) {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<Boolean, String> create(RequestHttp<?, ?> requestHttp) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new MaterialDeleteApacheHttpRequestExecutor(requestHttp);
+        return new MaterialDeleteApacheHttpRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp);
       case JODD_HTTP:
-        return new MaterialDeleteJoddHttpRequestExecutor(requestHttp);
+        return new MaterialDeleteJoddHttpRequestExecutor((RequestHttp<HttpConnectionProvider, ProxyInfo>) requestHttp);
       case OK_HTTP:
-        return new MaterialDeleteOkhttpRequestExecutor(requestHttp);
+        return new MaterialDeleteOkhttpRequestExecutor((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp);
+      case HTTP_COMPONENTS:
+        return new MaterialDeleteHttpComponentsRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp);
       default:
-        return null;
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoApacheHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoApacheHttpRequestExecutor.java
index a4c92cd55c..0059e17295 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoApacheHttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoApacheHttpRequestExecutor.java
@@ -29,7 +29,7 @@
 public class MaterialNewsInfoApacheHttpRequestExecutor
   extends MaterialNewsInfoRequestExecutor<CloseableHttpClient, HttpHost> {
 
-  public MaterialNewsInfoApacheHttpRequestExecutor(RequestHttp requestHttp) {
+  public MaterialNewsInfoApacheHttpRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
     super(requestHttp);
   }
 
@@ -51,8 +51,6 @@ public WxMpMaterialNews execute(String uri, String materialId, WxType wxType) th
       } else {
         return WxMpGsonBuilder.create().fromJson(responseContent, WxMpMaterialNews.class);
       }
-    } finally {
-      httpPost.releaseConnection();
     }
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoHttpComponentsRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoHttpComponentsRequestExecutor.java
new file mode 100644
index 0000000000..ddf3ad6762
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoHttpComponentsRequestExecutor.java
@@ -0,0 +1,46 @@
+package me.chanjar.weixin.mp.util.requestexecuter.material;
+
+import com.google.common.collect.ImmutableMap;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
+import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+
+import java.io.IOException;
+
+@Slf4j
+public class MaterialNewsInfoHttpComponentsRequestExecutor extends MaterialNewsInfoRequestExecutor<CloseableHttpClient, HttpHost> {
+
+  public MaterialNewsInfoHttpComponentsRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
+
+  @Override
+  public WxMpMaterialNews execute(String uri, String materialId, WxType wxType) throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+
+    httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(ImmutableMap.of("media_id", materialId))));
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    log.debug("响应原始数据：{}", responseContent);
+    WxError error = WxError.fromJson(responseContent, WxType.MP);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
+    } else {
+      return WxMpGsonBuilder.create().fromJson(responseContent, WxMpMaterialNews.class);
+    }
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoJoddHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoJoddHttpRequestExecutor.java
index 780c0734e1..d1be53b923 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoJoddHttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoJoddHttpRequestExecutor.java
@@ -5,7 +5,6 @@
 import jodd.http.HttpRequest;
 import jodd.http.HttpResponse;
 import jodd.http.ProxyInfo;
-import jodd.util.StringPool;
 
 import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.enums.WxType;
@@ -15,8 +14,6 @@
 import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews;
 import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
@@ -26,7 +23,7 @@
  */
 @Slf4j
 public class MaterialNewsInfoJoddHttpRequestExecutor extends MaterialNewsInfoRequestExecutor<HttpConnectionProvider, ProxyInfo> {
-  public MaterialNewsInfoJoddHttpRequestExecutor(RequestHttp requestHttp) {
+  public MaterialNewsInfoJoddHttpRequestExecutor(RequestHttp<HttpConnectionProvider, ProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoOkhttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoOkhttpRequestExecutor.java
index 2e3f14dddd..25e0074e9e 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoOkhttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoOkhttpRequestExecutor.java
@@ -22,7 +22,7 @@
  */
 @Slf4j
 public class MaterialNewsInfoOkhttpRequestExecutor extends MaterialNewsInfoRequestExecutor<OkHttpClient, OkHttpProxyInfo> {
-  public MaterialNewsInfoOkhttpRequestExecutor(RequestHttp requestHttp) {
+  public MaterialNewsInfoOkhttpRequestExecutor(RequestHttp<OkHttpClient, OkHttpProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoRequestExecutor.java
index 41374809c6..ca06327abd 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialNewsInfoRequestExecutor.java
@@ -1,18 +1,22 @@
 package me.chanjar.weixin.mp.util.requestexecuter.material;
 
-import java.io.IOException;
-
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.ResponseHandler;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
 import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews;
+import okhttp3.OkHttpClient;
+
+import java.io.IOException;
 
 public abstract class MaterialNewsInfoRequestExecutor<H, P> implements RequestExecutor<WxMpMaterialNews, String> {
   protected RequestHttp<H, P> requestHttp;
 
-  public MaterialNewsInfoRequestExecutor(RequestHttp requestHttp) {
+  public MaterialNewsInfoRequestExecutor(RequestHttp<H, P> requestHttp) {
     this.requestHttp = requestHttp;
   }
 
@@ -21,17 +25,21 @@ public void execute(String uri, String data, ResponseHandler<WxMpMaterialNews> h
     handler.handle(this.execute(uri, data, wxType));
   }
 
-  public static RequestExecutor<WxMpMaterialNews, String> create(RequestHttp requestHttp) {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<WxMpMaterialNews, String> create(RequestHttp<?, ?> requestHttp) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new MaterialNewsInfoApacheHttpRequestExecutor(requestHttp);
+        return new MaterialNewsInfoApacheHttpRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp);
       case JODD_HTTP:
-        return new MaterialNewsInfoJoddHttpRequestExecutor(requestHttp);
+        return new MaterialNewsInfoJoddHttpRequestExecutor((RequestHttp<HttpConnectionProvider, ProxyInfo>) requestHttp);
       case OK_HTTP:
-        return new MaterialNewsInfoOkhttpRequestExecutor(requestHttp);
+        return new MaterialNewsInfoOkhttpRequestExecutor((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp);
+      case HTTP_COMPONENTS:
+        return new MaterialNewsInfoHttpComponentsRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp);
       default:
-        //TODO 需要优化抛出异常
-        return null;
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadApacheHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadApacheHttpRequestExecutor.java
index 6a31484420..bf1b42fb9b 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadApacheHttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadApacheHttpRequestExecutor.java
@@ -8,7 +8,6 @@
 import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 import me.chanjar.weixin.mp.bean.material.WxMpMaterial;
 import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult;
-import org.apache.http.Consts;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.methods.CloseableHttpResponse;
@@ -22,13 +21,14 @@
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 import java.util.Map;
 
 /**
  * Created by ecoolper on 2017/5/5.
  */
 public class MaterialUploadApacheHttpRequestExecutor extends MaterialUploadRequestExecutor<CloseableHttpClient, HttpHost> {
-  public MaterialUploadApacheHttpRequestExecutor(RequestHttp requestHttp) {
+  public MaterialUploadApacheHttpRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
     super(requestHttp);
   }
 
@@ -56,7 +56,7 @@ public WxMpMaterialUploadResult execute(String uri, WxMpMaterial material, WxTyp
     Map<String, String> form = material.getForm();
     if (material.getForm() != null) {
       multipartEntityBuilder.addPart("description",
-        new StringBody(WxGsonBuilder.create().toJson(form), ContentType.create("text/plain", Consts.UTF_8)));
+        new StringBody(WxGsonBuilder.create().toJson(form), ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8)));
     }
     httpPost.setEntity(multipartEntityBuilder.build());
 
@@ -68,8 +68,6 @@ public WxMpMaterialUploadResult execute(String uri, WxMpMaterial material, WxTyp
       } else {
         return WxMpMaterialUploadResult.fromJson(responseContent);
       }
-    } finally {
-      httpPost.releaseConnection();
     }
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadHttpComponentsRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadHttpComponentsRequestExecutor.java
new file mode 100644
index 0000000000..05ae0fe506
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadHttpComponentsRequestExecutor.java
@@ -0,0 +1,67 @@
+package me.chanjar.weixin.mp.util.requestexecuter.material;
+
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
+import me.chanjar.weixin.mp.bean.material.WxMpMaterial;
+import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
+import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
+import org.apache.hc.client5.http.entity.mime.StringBody;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+
+public class MaterialUploadHttpComponentsRequestExecutor extends MaterialUploadRequestExecutor<CloseableHttpClient, HttpHost> {
+  public MaterialUploadHttpComponentsRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
+
+  @Override
+  public WxMpMaterialUploadResult execute(String uri, WxMpMaterial material, WxType wxType) throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig response = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(response);
+    }
+
+    if (material == null) {
+      throw new WxErrorException("非法请求，material参数为空");
+    }
+
+    File file = material.getFile();
+    if (file == null || !file.exists()) {
+      throw new FileNotFoundException();
+    }
+
+    MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
+    multipartEntityBuilder
+      .addBinaryBody("media", file)
+      .setMode(HttpMultipartMode.EXTENDED);
+    Map<String, String> form = material.getForm();
+    if (material.getForm() != null) {
+      multipartEntityBuilder.addPart("description",
+        new StringBody(WxGsonBuilder.create().toJson(form), ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8)));
+    }
+    httpPost.setEntity(multipartEntityBuilder.build());
+
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, WxType.MP);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
+    } else {
+      return WxMpMaterialUploadResult.fromJson(responseContent);
+    }
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadJoddHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadJoddHttpRequestExecutor.java
index d4c4dfbf89..23740328f2 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadJoddHttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadJoddHttpRequestExecutor.java
@@ -4,7 +4,6 @@
 import jodd.http.HttpRequest;
 import jodd.http.HttpResponse;
 import jodd.http.ProxyInfo;
-import jodd.util.StringPool;
 
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
@@ -24,7 +23,7 @@
  * Created by ecoolper on 2017/5/5.
  */
 public class MaterialUploadJoddHttpRequestExecutor extends MaterialUploadRequestExecutor<HttpConnectionProvider, ProxyInfo> {
-  public MaterialUploadJoddHttpRequestExecutor(RequestHttp requestHttp) {
+  public MaterialUploadJoddHttpRequestExecutor(RequestHttp<HttpConnectionProvider, ProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadOkhttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadOkhttpRequestExecutor.java
index 7416f94f0e..20e4622415 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadOkhttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadOkhttpRequestExecutor.java
@@ -23,7 +23,7 @@
 public class MaterialUploadOkhttpRequestExecutor extends MaterialUploadRequestExecutor<OkHttpClient, OkHttpProxyInfo> {
   private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
-  public MaterialUploadOkhttpRequestExecutor(RequestHttp requestHttp) {
+  public MaterialUploadOkhttpRequestExecutor(RequestHttp<OkHttpClient, OkHttpProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadRequestExecutor.java
index 9044d052a8..76ad3f88fa 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialUploadRequestExecutor.java
@@ -1,14 +1,18 @@
 package me.chanjar.weixin.mp.util.requestexecuter.material;
 
-import java.io.IOException;
-
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.ResponseHandler;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
 import me.chanjar.weixin.mp.bean.material.WxMpMaterial;
 import me.chanjar.weixin.mp.bean.material.WxMpMaterialUploadResult;
+import okhttp3.OkHttpClient;
+
+import java.io.IOException;
 
 /**
  * @author codepiano
@@ -16,7 +20,7 @@
 public abstract class MaterialUploadRequestExecutor<H, P> implements RequestExecutor<WxMpMaterialUploadResult, WxMpMaterial> {
   protected RequestHttp<H, P> requestHttp;
 
-  public MaterialUploadRequestExecutor(RequestHttp requestHttp) {
+  public MaterialUploadRequestExecutor(RequestHttp<H, P> requestHttp) {
     this.requestHttp = requestHttp;
   }
 
@@ -25,16 +29,21 @@ public void execute(String uri, WxMpMaterial data, ResponseHandler<WxMpMaterialU
     handler.handle(this.execute(uri, data, wxType));
   }
 
-  public static RequestExecutor<WxMpMaterialUploadResult, WxMpMaterial> create(RequestHttp requestHttp) {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<WxMpMaterialUploadResult, WxMpMaterial> create(RequestHttp<?, ?> requestHttp) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new MaterialUploadApacheHttpRequestExecutor(requestHttp);
+        return new MaterialUploadApacheHttpRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp);
       case JODD_HTTP:
-        return new MaterialUploadJoddHttpRequestExecutor(requestHttp);
+        return new MaterialUploadJoddHttpRequestExecutor((RequestHttp<HttpConnectionProvider, ProxyInfo>) requestHttp);
       case OK_HTTP:
-        return new MaterialUploadOkhttpRequestExecutor(requestHttp);
+        return new MaterialUploadOkhttpRequestExecutor((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp);
+      case HTTP_COMPONENTS:
+        return new MaterialUploadHttpComponentsRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp);
       default:
-        return null;
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoApacheHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoApacheHttpRequestExecutor.java
index 7034379fbe..387ed50c9e 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoApacheHttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoApacheHttpRequestExecutor.java
@@ -9,7 +9,6 @@
 import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.impl.client.CloseableHttpClient;
@@ -22,7 +21,7 @@
  * Created by ecoolper on 2017/5/5.
  */
 public class MaterialVideoInfoApacheHttpRequestExecutor extends MaterialVideoInfoRequestExecutor<CloseableHttpClient, HttpHost> {
-  public MaterialVideoInfoApacheHttpRequestExecutor(RequestHttp requestHttp) {
+  public MaterialVideoInfoApacheHttpRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
     super(requestHttp);
   }
 
@@ -37,16 +36,12 @@ public WxMpMaterialVideoInfoResult execute(String uri, String materialId, WxType
     Map<String, String> params = new HashMap<>();
     params.put("media_id", materialId);
     httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params)));
-    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
-      String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
-      WxError error = WxError.fromJson(responseContent, WxType.MP);
-      if (error.getErrorCode() != 0) {
-        throw new WxErrorException(error);
-      } else {
-        return WxMpMaterialVideoInfoResult.fromJson(responseContent);
-      }
-    } finally {
-      httpPost.releaseConnection();
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, WxType.MP);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
+    } else {
+      return WxMpMaterialVideoInfoResult.fromJson(responseContent);
     }
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoHttpComponentsRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoHttpComponentsRequestExecutor.java
new file mode 100644
index 0000000000..2a147609d5
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoHttpComponentsRequestExecutor.java
@@ -0,0 +1,44 @@
+package me.chanjar.weixin.mp.util.requestexecuter.material;
+
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
+import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MaterialVideoInfoHttpComponentsRequestExecutor extends MaterialVideoInfoRequestExecutor<CloseableHttpClient, HttpHost> {
+  public MaterialVideoInfoHttpComponentsRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
+
+  @Override
+  public WxMpMaterialVideoInfoResult execute(String uri, String materialId, WxType wxType) throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+
+    Map<String, String> params = new HashMap<>();
+    params.put("media_id", materialId);
+    httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params)));
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, WxType.MP);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
+    } else {
+      return WxMpMaterialVideoInfoResult.fromJson(responseContent);
+    }
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoJoddHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoJoddHttpRequestExecutor.java
index 9149d46794..1ea90199fb 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoJoddHttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoJoddHttpRequestExecutor.java
@@ -4,7 +4,6 @@
 import jodd.http.HttpRequest;
 import jodd.http.HttpResponse;
 import jodd.http.ProxyInfo;
-import jodd.util.StringPool;
 
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
@@ -19,7 +18,7 @@
  * Created by ecoolper on 2017/5/5.
  */
 public class MaterialVideoInfoJoddHttpRequestExecutor extends MaterialVideoInfoRequestExecutor<HttpConnectionProvider, ProxyInfo> {
-  public MaterialVideoInfoJoddHttpRequestExecutor(RequestHttp requestHttp) {
+  public MaterialVideoInfoJoddHttpRequestExecutor(RequestHttp<HttpConnectionProvider, ProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoOkhttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoOkhttpRequestExecutor.java
index 2e38ab003b..d548fcb4ae 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoOkhttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoOkhttpRequestExecutor.java
@@ -20,7 +20,7 @@
 public class MaterialVideoInfoOkhttpRequestExecutor extends MaterialVideoInfoRequestExecutor<OkHttpClient, OkHttpProxyInfo> {
   private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
-  public MaterialVideoInfoOkhttpRequestExecutor(RequestHttp requestHttp) {
+  public MaterialVideoInfoOkhttpRequestExecutor(RequestHttp<OkHttpClient, OkHttpProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoRequestExecutor.java
index 5ea6fae0b2..b4073c7fec 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVideoInfoRequestExecutor.java
@@ -1,19 +1,22 @@
 package me.chanjar.weixin.mp.util.requestexecuter.material;
 
-
-import java.io.IOException;
-
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.ResponseHandler;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
 import me.chanjar.weixin.mp.bean.material.WxMpMaterialVideoInfoResult;
+import okhttp3.OkHttpClient;
+
+import java.io.IOException;
 
 public abstract class MaterialVideoInfoRequestExecutor<H, P> implements RequestExecutor<WxMpMaterialVideoInfoResult, String> {
   protected RequestHttp<H, P> requestHttp;
 
-  public MaterialVideoInfoRequestExecutor(RequestHttp requestHttp) {
+  public MaterialVideoInfoRequestExecutor(RequestHttp<H, P> requestHttp) {
     this.requestHttp = requestHttp;
   }
 
@@ -22,16 +25,21 @@ public void execute(String uri, String data, ResponseHandler<WxMpMaterialVideoIn
     handler.handle(this.execute(uri, data, wxType));
   }
 
-  public static RequestExecutor<WxMpMaterialVideoInfoResult, String> create(RequestHttp requestHttp) {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<WxMpMaterialVideoInfoResult, String> create(RequestHttp<?, ?> requestHttp) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new MaterialVideoInfoApacheHttpRequestExecutor(requestHttp);
+        return new MaterialVideoInfoApacheHttpRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp);
       case JODD_HTTP:
-        return new MaterialVideoInfoJoddHttpRequestExecutor(requestHttp);
+        return new MaterialVideoInfoJoddHttpRequestExecutor((RequestHttp<HttpConnectionProvider, ProxyInfo>) requestHttp);
       case OK_HTTP:
-        return new MaterialVideoInfoOkhttpRequestExecutor(requestHttp);
+        return new MaterialVideoInfoOkhttpRequestExecutor((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp);
+      case HTTP_COMPONENTS:
+        return new MaterialVideoInfoHttpComponentsRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp);
       default:
-        return null;
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadApacheHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadApacheHttpRequestExecutor.java
index d11591edf1..05395319cc 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadApacheHttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadApacheHttpRequestExecutor.java
@@ -26,7 +26,7 @@
  * Created by ecoolper on 2017/5/5.
  */
 public class MaterialVoiceAndImageDownloadApacheHttpRequestExecutor extends MaterialVoiceAndImageDownloadRequestExecutor<CloseableHttpClient, HttpHost> {
-  public MaterialVoiceAndImageDownloadApacheHttpRequestExecutor(RequestHttp requestHttp, File tmpDirFile) {
+  public MaterialVoiceAndImageDownloadApacheHttpRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp, File tmpDirFile) {
     super(requestHttp, tmpDirFile);
   }
 
@@ -57,8 +57,6 @@ public InputStream execute(String uri, String materialId, WxType wxType) throws
         }
       }
       return new ByteArrayInputStream(responseContent);
-    } finally {
-      httpPost.releaseConnection();
     }
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadHttpComponentsRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadHttpComponentsRequestExecutor.java
new file mode 100644
index 0000000000..ac7df1a0ce
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadHttpComponentsRequestExecutor.java
@@ -0,0 +1,64 @@
+package me.chanjar.weixin.mp.util.requestexecuter.material;
+
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.hc.InputStreamResponseHandler;
+import me.chanjar.weixin.common.util.json.WxGsonBuilder;
+import org.apache.commons.io.IOUtils;
+import org.apache.hc.client5.http.ClientProtocolException;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MaterialVoiceAndImageDownloadHttpComponentsRequestExecutor
+  extends MaterialVoiceAndImageDownloadRequestExecutor<CloseableHttpClient, HttpHost> {
+  public MaterialVoiceAndImageDownloadHttpComponentsRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp, File tmpDirFile) {
+    super(requestHttp, tmpDirFile);
+  }
+
+  @Override
+  public InputStream execute(String uri, String materialId, WxType wxType) throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+
+    Map<String, String> params = new HashMap<>();
+    params.put("media_id", materialId);
+    httpPost.setEntity(new StringEntity(WxGsonBuilder.create().toJson(params)));
+    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost);
+         InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) {
+      // 下载媒体文件出错
+      byte[] responseContent = IOUtils.toByteArray(inputStream);
+      String responseContentString = new String(responseContent, StandardCharsets.UTF_8);
+      if (responseContentString.length() <= 215) {
+        try {
+          WxError wxError = WxGsonBuilder.create().fromJson(responseContentString, WxError.class);
+          if (wxError.getErrorCode() != 0) {
+            throw new WxErrorException(wxError);
+          }
+        } catch (com.google.gson.JsonSyntaxException ex) {
+          return new ByteArrayInputStream(responseContent);
+        }
+      }
+      return new ByteArrayInputStream(responseContent);
+    } catch (HttpException httpException) {
+      throw new ClientProtocolException(httpException.getMessage(), httpException);
+    }
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadJoddHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadJoddHttpRequestExecutor.java
index c946e9b4b6..b1264864e5 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadJoddHttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadJoddHttpRequestExecutor.java
@@ -4,7 +4,6 @@
 import jodd.http.HttpRequest;
 import jodd.http.HttpResponse;
 import jodd.http.ProxyInfo;
-import jodd.util.StringPool;
 
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
@@ -23,7 +22,7 @@
  * Created by ecoolper on 2017/5/5.
  */
 public class MaterialVoiceAndImageDownloadJoddHttpRequestExecutor extends MaterialVoiceAndImageDownloadRequestExecutor<HttpConnectionProvider, ProxyInfo> {
-  public MaterialVoiceAndImageDownloadJoddHttpRequestExecutor(RequestHttp requestHttp, File tmpDirFile) {
+  public MaterialVoiceAndImageDownloadJoddHttpRequestExecutor(RequestHttp<HttpConnectionProvider, ProxyInfo> requestHttp, File tmpDirFile) {
     super(requestHttp, tmpDirFile);
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadOkhttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadOkhttpRequestExecutor.java
index b77958a4e9..3823440490 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadOkhttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadOkhttpRequestExecutor.java
@@ -8,8 +8,6 @@
 import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
 import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 import okhttp3.*;
-import okio.BufferedSink;
-import okio.Okio;
 import org.apache.commons.io.IOUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -22,7 +20,7 @@
 public class MaterialVoiceAndImageDownloadOkhttpRequestExecutor extends MaterialVoiceAndImageDownloadRequestExecutor<OkHttpClient, OkHttpProxyInfo> {
   private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
-  public MaterialVoiceAndImageDownloadOkhttpRequestExecutor(RequestHttp requestHttp, File tmpDirFile) {
+  public MaterialVoiceAndImageDownloadOkhttpRequestExecutor(RequestHttp<OkHttpClient, OkHttpProxyInfo> requestHttp, File tmpDirFile) {
     super(requestHttp, tmpDirFile);
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadRequestExecutor.java
index b482ddbcd1..42994a7423 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/material/MaterialVoiceAndImageDownloadRequestExecutor.java
@@ -4,17 +4,21 @@
 import java.io.IOException;
 import java.io.InputStream;
 
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.ResponseHandler;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
+import okhttp3.OkHttpClient;
 
 public abstract class MaterialVoiceAndImageDownloadRequestExecutor<H, P> implements RequestExecutor<InputStream, String> {
   protected RequestHttp<H, P> requestHttp;
   protected File tmpDirFile;
 
-  public MaterialVoiceAndImageDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) {
+  public MaterialVoiceAndImageDownloadRequestExecutor(RequestHttp<H, P> requestHttp, File tmpDirFile) {
     this.requestHttp = requestHttp;
     this.tmpDirFile = tmpDirFile;
   }
@@ -24,16 +28,21 @@ public void execute(String uri, String data, ResponseHandler<InputStream> handle
     handler.handle(this.execute(uri, data, wxType));
   }
 
-  public static RequestExecutor<InputStream, String> create(RequestHttp requestHttp, File tmpDirFile) {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<InputStream, String> create(RequestHttp<?, ?> requestHttp, File tmpDirFile) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new MaterialVoiceAndImageDownloadApacheHttpRequestExecutor(requestHttp, tmpDirFile);
+        return new MaterialVoiceAndImageDownloadApacheHttpRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp, tmpDirFile);
       case JODD_HTTP:
-        return new MaterialVoiceAndImageDownloadJoddHttpRequestExecutor(requestHttp, tmpDirFile);
+        return new MaterialVoiceAndImageDownloadJoddHttpRequestExecutor((RequestHttp<HttpConnectionProvider, ProxyInfo>) requestHttp, tmpDirFile);
       case OK_HTTP:
-        return new MaterialVoiceAndImageDownloadOkhttpRequestExecutor(requestHttp, tmpDirFile);
+        return new MaterialVoiceAndImageDownloadOkhttpRequestExecutor((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp, tmpDirFile);
+      case HTTP_COMPONENTS:
+        return new MaterialVoiceAndImageDownloadHttpComponentsRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp, tmpDirFile);
       default:
-        return null;
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadApacheHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadApacheHttpRequestExecutor.java
index 7c4ba18598..495f144f3d 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadApacheHttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadApacheHttpRequestExecutor.java
@@ -11,7 +11,6 @@
 import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpPost;
-import org.apache.http.entity.ContentType;
 import org.apache.http.entity.mime.HttpMultipartMode;
 import org.apache.http.entity.mime.MultipartEntityBuilder;
 import org.apache.http.impl.client.CloseableHttpClient;
@@ -25,7 +24,7 @@
  * @author ecoolper
  */
 public class MediaImgUploadApacheHttpRequestExecutor extends MediaImgUploadRequestExecutor<CloseableHttpClient, HttpHost> {
-  public MediaImgUploadApacheHttpRequestExecutor(RequestHttp requestHttp) {
+  public MediaImgUploadApacheHttpRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
     super(requestHttp);
   }
 
@@ -56,8 +55,6 @@ public WxMediaImgUploadResult execute(String uri, File data, WxType wxType) thro
       }
 
       return WxMediaImgUploadResult.fromJson(responseContent);
-    } finally {
-      httpPost.releaseConnection();
     }
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadHttpComponentsRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadHttpComponentsRequestExecutor.java
new file mode 100644
index 0000000000..be1d12631d
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadHttpComponentsRequestExecutor.java
@@ -0,0 +1,52 @@
+package me.chanjar.weixin.mp.util.requestexecuter.media;
+
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler;
+import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
+import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.File;
+import java.io.IOException;
+
+public class MediaImgUploadHttpComponentsRequestExecutor extends MediaImgUploadRequestExecutor<CloseableHttpClient, HttpHost> {
+  public MediaImgUploadHttpComponentsRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
+
+  @Override
+  public WxMediaImgUploadResult execute(String uri, File data, WxType wxType) throws WxErrorException, IOException {
+    if (data == null) {
+      throw new WxErrorException("文件对象为空");
+    }
+
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+
+    HttpEntity entity = MultipartEntityBuilder
+      .create()
+      .addBinaryBody("media", data)
+      .setMode(HttpMultipartMode.EXTENDED)
+      .build();
+    httpPost.setEntity(entity);
+
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, WxType.MP);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
+    }
+
+    return WxMediaImgUploadResult.fromJson(responseContent);
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadHttpRequestExecutor.java
index 1ca4c7c8bf..138d8b5d3d 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadHttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadHttpRequestExecutor.java
@@ -4,7 +4,6 @@
 import jodd.http.HttpRequest;
 import jodd.http.HttpResponse;
 import jodd.http.ProxyInfo;
-import jodd.util.StringPool;
 
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
@@ -22,7 +21,7 @@
  * @author ecoolper
  */
 public class MediaImgUploadHttpRequestExecutor extends MediaImgUploadRequestExecutor<HttpConnectionProvider, ProxyInfo> {
-  public MediaImgUploadHttpRequestExecutor(RequestHttp requestHttp) {
+  public MediaImgUploadHttpRequestExecutor(RequestHttp<HttpConnectionProvider, ProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadOkhttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadOkhttpRequestExecutor.java
index 27677b74b4..7a6a980afe 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadOkhttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadOkhttpRequestExecutor.java
@@ -21,7 +21,7 @@
 public class MediaImgUploadOkhttpRequestExecutor extends MediaImgUploadRequestExecutor<OkHttpClient, OkHttpProxyInfo> {
   private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
-  public MediaImgUploadOkhttpRequestExecutor(RequestHttp requestHttp) {
+  public MediaImgUploadOkhttpRequestExecutor(RequestHttp<OkHttpClient, OkHttpProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadRequestExecutor.java
index b5f42e0f8d..40a9d47155 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/media/MediaImgUploadRequestExecutor.java
@@ -3,12 +3,16 @@
 import java.io.File;
 import java.io.IOException;
 
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.ResponseHandler;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
 import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult;
+import okhttp3.OkHttpClient;
 
 /**
  * @author miller
@@ -16,7 +20,7 @@
 public abstract class MediaImgUploadRequestExecutor<H, P> implements RequestExecutor<WxMediaImgUploadResult, File> {
   protected RequestHttp<H, P> requestHttp;
 
-  public MediaImgUploadRequestExecutor(RequestHttp requestHttp) {
+  public MediaImgUploadRequestExecutor(RequestHttp<H, P> requestHttp) {
     this.requestHttp = requestHttp;
   }
 
@@ -25,16 +29,21 @@ public void execute(String uri, File data, ResponseHandler<WxMediaImgUploadResul
     handler.handle(this.execute(uri, data, wxType));
   }
 
-  public static RequestExecutor<WxMediaImgUploadResult, File> create(RequestHttp requestHttp) {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<WxMediaImgUploadResult, File> create(RequestHttp<?, ?> requestHttp) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new MediaImgUploadApacheHttpRequestExecutor(requestHttp);
+        return new MediaImgUploadApacheHttpRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp);
       case JODD_HTTP:
-        return new MediaImgUploadHttpRequestExecutor(requestHttp);
+        return new MediaImgUploadHttpRequestExecutor((RequestHttp<HttpConnectionProvider, ProxyInfo>) requestHttp);
       case OK_HTTP:
-        return new MediaImgUploadOkhttpRequestExecutor(requestHttp);
+        return new MediaImgUploadOkhttpRequestExecutor((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp);
+      case HTTP_COMPONENTS:
+        return new MediaImgUploadHttpComponentsRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp);
       default:
-        return null;
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeApacheHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeApacheHttpRequestExecutor.java
index 2c8e5b5721..3ff6a5a369 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeApacheHttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeApacheHttpRequestExecutor.java
@@ -26,7 +26,7 @@
  * Created by ecoolper on 2017/5/5.
  */
 public class QrCodeApacheHttpRequestExecutor extends QrCodeRequestExecutor<CloseableHttpClient, HttpHost> {
-  public QrCodeApacheHttpRequestExecutor(RequestHttp requestHttp) {
+  public QrCodeApacheHttpRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
     super(requestHttp);
   }
 
@@ -59,8 +59,6 @@ public File execute(String uri, WxMpQrCodeTicket ticket, WxType wxType) throws W
         }
       }
       return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg");
-    } finally {
-      httpGet.releaseConnection();
     }
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeHttpComponentsRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeHttpComponentsRequestExecutor.java
new file mode 100644
index 0000000000..fbf8af0783
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeHttpComponentsRequestExecutor.java
@@ -0,0 +1,67 @@
+package me.chanjar.weixin.mp.util.requestexecuter.qrcode;
+
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.fs.FileUtils;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.hc.InputStreamResponseHandler;
+import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler;
+import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
+import org.apache.hc.client5.http.ClientProtocolException;
+import org.apache.hc.client5.http.classic.methods.HttpGet;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLEncoder;
+import java.util.UUID;
+
+/**
+ * @author altusea
+ */
+public class QrCodeHttpComponentsRequestExecutor extends QrCodeRequestExecutor<CloseableHttpClient, HttpHost> {
+  public QrCodeHttpComponentsRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
+
+  @Override
+  public File execute(String uri, WxMpQrCodeTicket ticket, WxType wxType) throws WxErrorException, IOException {
+    if (ticket != null) {
+      if (uri.indexOf('?') == -1) {
+        uri += '?';
+      }
+      uri += uri.endsWith("?")
+        ? "ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8")
+        : "&ticket=" + URLEncoder.encode(ticket.getTicket(), "UTF-8");
+    }
+
+    HttpGet httpGet = new HttpGet(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpGet.setConfig(config);
+    }
+
+    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpGet);
+         InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response)) {
+      Header[] contentTypeHeader = response.getHeaders("Content-Type");
+      if (contentTypeHeader != null && contentTypeHeader.length > 0) {
+        // 出错
+        if (ContentType.TEXT_PLAIN.getMimeType().equals(ContentType.parse(contentTypeHeader[0].getValue()).getMimeType())) {
+          String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
+          throw new WxErrorException(WxError.fromJson(responseContent, WxType.MP));
+        }
+      }
+      return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg");
+    } catch (HttpException httpException) {
+      throw new ClientProtocolException(httpException.getMessage(), httpException);
+    }
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeJoddHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeJoddHttpRequestExecutor.java
index 32d3d3ca75..9fcf7768ae 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeJoddHttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeJoddHttpRequestExecutor.java
@@ -5,7 +5,6 @@
 import jodd.http.HttpResponse;
 import jodd.http.ProxyInfo;
 import jodd.net.MimeTypes;
-import jodd.util.StringPool;
 
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
@@ -26,7 +25,7 @@
  * Created by ecoolper on 2017/5/5.
  */
 public class QrCodeJoddHttpRequestExecutor extends QrCodeRequestExecutor<HttpConnectionProvider, ProxyInfo> {
-  public QrCodeJoddHttpRequestExecutor(RequestHttp requestHttp) {
+  public QrCodeJoddHttpRequestExecutor(RequestHttp<HttpConnectionProvider, ProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeOkhttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeOkhttpRequestExecutor.java
index f6f2036ce1..42289e775c 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeOkhttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeOkhttpRequestExecutor.java
@@ -27,7 +27,7 @@
 public class QrCodeOkhttpRequestExecutor extends QrCodeRequestExecutor<OkHttpClient, OkHttpProxyInfo> {
   private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
-  public QrCodeOkhttpRequestExecutor(RequestHttp requestHttp) {
+  public QrCodeOkhttpRequestExecutor(RequestHttp<OkHttpClient, OkHttpProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeRequestExecutor.java
index 4ca5dbc0c1..6407ac11ad 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/qrcode/QrCodeRequestExecutor.java
@@ -3,13 +3,16 @@
 import java.io.File;
 import java.io.IOException;
 
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
 import me.chanjar.weixin.common.enums.WxType;
-import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.ResponseHandler;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
 import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
+import okhttp3.OkHttpClient;
 
 /**
  * 获得QrCode图片 请求执行器.
@@ -19,7 +22,7 @@
 public abstract class QrCodeRequestExecutor<H, P> implements RequestExecutor<File, WxMpQrCodeTicket> {
   protected RequestHttp<H, P> requestHttp;
 
-  public QrCodeRequestExecutor(RequestHttp requestHttp) {
+  public QrCodeRequestExecutor(RequestHttp<H, P> requestHttp) {
     this.requestHttp = requestHttp;
   }
 
@@ -28,16 +31,21 @@ public void execute(String uri, WxMpQrCodeTicket data, ResponseHandler<File> han
     handler.handle(this.execute(uri, data, wxType));
   }
 
-  public static RequestExecutor<File, WxMpQrCodeTicket> create(RequestHttp requestHttp) throws WxErrorException {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<File, WxMpQrCodeTicket> create(RequestHttp<?, ?> requestHttp) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new QrCodeApacheHttpRequestExecutor(requestHttp);
+        return new QrCodeApacheHttpRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp);
       case JODD_HTTP:
-        return new QrCodeJoddHttpRequestExecutor(requestHttp);
+        return new QrCodeJoddHttpRequestExecutor((RequestHttp<HttpConnectionProvider, ProxyInfo>) requestHttp);
       case OK_HTTP:
-        return new QrCodeOkhttpRequestExecutor(requestHttp);
+        return new QrCodeOkhttpRequestExecutor((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp);
+      case HTTP_COMPONENTS:
+        return new QrCodeHttpComponentsRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp);
       default:
-        throw new WxErrorException("不支持的http框架");
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadApacheHttpRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadApacheHttpRequestExecutor.java
index 06aa1fcda1..f384f8f567 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadApacheHttpRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadApacheHttpRequestExecutor.java
@@ -8,9 +8,7 @@
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpPost;
-import org.apache.http.entity.ContentType;
 import org.apache.http.entity.mime.HttpMultipartMode;
 import org.apache.http.entity.mime.MultipartEntityBuilder;
 import org.apache.http.impl.client.CloseableHttpClient;
@@ -26,7 +24,7 @@
  * @author <a href="https://github.com/binarywang">Binary Wang</a>
  */
 public class VoiceUploadApacheHttpRequestExecutor extends VoiceUploadRequestExecutor<CloseableHttpClient, HttpHost> {
-  public VoiceUploadApacheHttpRequestExecutor(RequestHttp requestHttp) {
+  public VoiceUploadApacheHttpRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
     super(requestHttp);
   }
 
@@ -49,16 +47,11 @@ public Boolean execute(String uri, File data, WxType wxType) throws WxErrorExcep
       .build();
     httpPost.setEntity(entity);
 
-    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
-      String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
-      WxError error = WxError.fromJson(responseContent, WxType.MP);
-      if (error.getErrorCode() != 0) {
-        throw new WxErrorException(error);
-      }
-
-      return true;
-    } finally {
-      httpPost.releaseConnection();
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, WxType.MP);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
     }
+    return true;
   }
 }
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadHttpComponentsRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadHttpComponentsRequestExecutor.java
new file mode 100644
index 0000000000..1775f04aef
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadHttpComponentsRequestExecutor.java
@@ -0,0 +1,50 @@
+package me.chanjar.weixin.mp.util.requestexecuter.voice;
+
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
+import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.File;
+import java.io.IOException;
+
+public class VoiceUploadHttpComponentsRequestExecutor extends VoiceUploadRequestExecutor<CloseableHttpClient, HttpHost> {
+  public VoiceUploadHttpComponentsRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
+
+  @Override
+  public Boolean execute(String uri, File data, WxType wxType) throws WxErrorException, IOException {
+    if (data == null) {
+      throw new WxErrorException("文件对象为空");
+    }
+
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+
+    HttpEntity entity = MultipartEntityBuilder
+      .create()
+      .addBinaryBody("media", data)
+      .setMode(HttpMultipartMode.EXTENDED)
+      .build();
+    httpPost.setEntity(entity);
+
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    WxError error = WxError.fromJson(responseContent, WxType.MP);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
+    }
+    return true;
+  }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadRequestExecutor.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadRequestExecutor.java
index fa48c953f6..e8eb7cb9e9 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadRequestExecutor.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/util/requestexecuter/voice/VoiceUploadRequestExecutor.java
@@ -1,14 +1,14 @@
 package me.chanjar.weixin.mp.util.requestexecuter.voice;
 
-import java.io.File;
-import java.io.IOException;
-
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.ResponseHandler;
 
+import java.io.File;
+import java.io.IOException;
+
 /**
  * <pre>
  *  Created by BinaryWang on 2018/6/9.
@@ -19,7 +19,7 @@
 public abstract class VoiceUploadRequestExecutor<H, P> implements RequestExecutor<Boolean, File> {
   protected RequestHttp<H, P> requestHttp;
 
-  public VoiceUploadRequestExecutor(RequestHttp requestHttp) {
+  public VoiceUploadRequestExecutor(RequestHttp<H, P> requestHttp) {
     this.requestHttp = requestHttp;
   }
 
@@ -28,14 +28,17 @@ public void execute(String uri, File data, ResponseHandler<Boolean> handler, WxT
     handler.handle(this.execute(uri, data, wxType));
   }
 
-  public static RequestExecutor<Boolean, File> create(RequestHttp requestHttp) {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<Boolean, File> create(RequestHttp<?, ?> requestHttp) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new VoiceUploadApacheHttpRequestExecutor(requestHttp);
-      case JODD_HTTP:
-      case OK_HTTP:
+        return new VoiceUploadApacheHttpRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp);
+      case HTTP_COMPONENTS:
+        return new VoiceUploadHttpComponentsRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp);
       default:
-        return null;
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImplTest.java
index 89b2224053..4beced7c7c 100644
--- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImplTest.java
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImplTest.java
@@ -8,7 +8,7 @@
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.error.WxMpErrorMsgEnum;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.api.test.ApiTestModule;
@@ -237,7 +237,7 @@ public Object getRequestHttpProxy() {
       }
 
       @Override
-      public HttpType getRequestType() {
+      public HttpClientType getRequestType() {
         return null;
       }
     };
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpDraftServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpDraftServiceImplTest.java
index 15966d6727..77288d8d3b 100644
--- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpDraftServiceImplTest.java
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpDraftServiceImplTest.java
@@ -1,6 +1,7 @@
 package me.chanjar.weixin.mp.api.impl;
 
 import com.google.inject.Inject;
+import me.chanjar.weixin.common.api.WxConsts;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.api.test.ApiTestModule;
@@ -23,15 +24,15 @@
 public class WxMpDraftServiceImplTest {
 
   /**
-   * 1.先上传一个永久图片素材：me.chanjar.weixin.mp.api.impl.WxMpMaterialServiceImplTest.testUploadMaterial
+   * 1.先上传一个永久图片素材：{@link me.chanjar.weixin.mp.api.impl.WxMpMaterialServiceImplTest#testUploadMaterial}
    * 2.后续图文需要设置一个永久素材id
    */
-  final String thumbMediaId = "zUUtT8ZYeXzZ4slFbtnAkh7Yd-f45DbFoF9ERzVC6s4";
+  final String thumbMediaId = "-V3dxNv-eyJlImuJjWrmaTPt76BS6jHrL6-cGBlFPaXxAuv0qeJYV2p6Ezirr0zS";
 
   /**
    * 新增草稿后返回的id，后续查询、修改、删除，获取等需要使用
    */
-  final String mediaId = "zUUtT8ZYeXzZ4slFbtnAkpgGKyqnTsjtUvMdVBRWJVk";
+  final String mediaId = "-V3dxNv-eyJlImuJjWrmaZLwMkTKfDEhzq5NURU02H-k1qHMJ0lh9p0UU46w3rbd";
 
   @Inject
   protected WxMpService wxService;
@@ -114,6 +115,7 @@ public void testListDraft() throws WxErrorException {
     ,"total_count":1,"item_count":1}
 
     */
+    System.out.println(draftList);
     assertThat(draftList).isNotNull();
   }
 
@@ -124,5 +126,101 @@ public void testCountDraft() throws WxErrorException {
     assertThat(countDraft).isNotNull();
   }
 
+  //-----以下是图片类型草稿测试
+
+  /**
+   * 先上传一个永久图片素材：{@link me.chanjar.weixin.mp.api.impl.WxMpMaterialServiceImplTest#testUploadMaterial}
+   * 这里的图片，使用的是 mm.jpeg
+   */
+  @Test
+  public void testAddDraftPic() throws WxErrorException {
+    List<WxMpDraftArticles> draftArticleList = new ArrayList<>();
+    ArrayList<WxMpDraftImageInfo.ImageItem> imageItems = new ArrayList<>();
+    imageItems.add(new WxMpDraftImageInfo.ImageItem(thumbMediaId));
+
+    ArrayList<WxMpDraftCoverInfo.CropPercent> cropPercents = new ArrayList<>();
+    cropPercents.add(new WxMpDraftCoverInfo.CropPercent("1_1", "0.1", "0", "1", "0.9"));
+
+    WxMpDraftArticles draftArticle = WxMpDraftArticles.builder()
+      .articleType(WxConsts.ArticleType.NEWS_PIC)
+      .title("新建图片草稿")
+      .content("图片消息的具体内容")
+      // 打开评论、所有人可评论
+      .needOpenComment(1).onlyFansCanComment(0)
+      .imageInfo(WxMpDraftImageInfo.builder().imageList(imageItems).build())
+      .coverInfo(WxMpDraftCoverInfo.builder().cropPercentList(cropPercents).build())
+      .productInfo(WxMpDraftProductInfo.builder().footerProductInfo(new WxMpDraftProductInfo.FooterProductInfo("")).build())
+      .build();
+    draftArticleList.add(draftArticle);
+
+    WxMpAddDraft addDraft = WxMpAddDraft.builder().articles(draftArticleList).build();
+    String mediaId = this.wxService.getDraftService().addDraft(addDraft);
+    System.out.println(mediaId);
+    assertThat(mediaId).isNotNull();
+  }
+
+  @Test
+  public void testGetDraftPic() throws WxErrorException {
+    final WxMpDraftInfo draftInfo = this.wxService.getDraftService().getDraft(mediaId);
+    assertThat(draftInfo).isNotNull();
+    System.out.println(draftInfo.toJson());
+    // 【响应数据】：{
+    //     "news_item": [
+    //         {
+    //             "article_type": "newspic",
+    //             "title": "新建图片草稿",
+    //             "content": "图片消息的具体内容",
+    //             "thumb_media_id": "-V3dxNv-eyJlImuJjWrmaTPt76BS6jHrL6-cGBlFPaXxAuv0qeJYV2p6Ezirr0zS",
+    //             "need_open_comment": 1,
+    //             "only_fans_can_comment": 0,
+    //             "url": "http://mp.weixin.qq.com/s?__biz=MzkyNTg4NDM1NA==&tempkey=MTMyM18rUktkOHFIQm5Kd3U5Rk1yS2NRYWtyZWUyNDNwS2MxZTZ3VXBKTkVScExpUFdGYzN2X0IzOEl1NGxEMGFpYld6NmdvbE9UUzlyYUdiVklvWTQ2YlRzSkkzQlpWMEZpcG9JRWp5LWZCVVNoWURodUlfWnE4VWZVQnlPd2VaUkg5SGREYUd3TW1wQkhlbTFuenBvRzFIbUxhMEJVbEo0Z3oyd2tnSGJBfn4%3D&chksm=423e8b9e75490288e8388c9ee91d6dad462bbce654742edd316622ab2b2fcfc593a4db58577b#rd",
+    //             "thumb_url": "http://mmbiz.qpic.cn/sz_mmbiz_jpg/s7FE7rYN42QgPuJeXX9MfNuJBiaoalrWv8fj4AEqnK0WBM3KzqS0DsqHIW4epA3cx1PGjpco87BTssgQibvSNBIQ/0?wx_fmt=jpeg",
+    //             "image_info": {
+    //                 "image_list": [
+    //                     {
+    //                         "image_media_id": "-V3dxNv-eyJlImuJjWrmaTPt76BS6jHrL6-cGBlFPaXxAuv0qeJYV2p6Ezirr0zS"
+    //                     }
+    //                 ]
+    //             }
+    //         }
+    //     ]
+    // }
+  }
+
+  @Test
+  public void testUpdateDraftPic() throws WxErrorException {
+    ArrayList<WxMpDraftImageInfo.ImageItem> imageItems = new ArrayList<>();
+    imageItems.add(new WxMpDraftImageInfo.ImageItem(thumbMediaId));
+    ArrayList<WxMpDraftCoverInfo.CropPercent> cropPercents = new ArrayList<>();
+    cropPercents.add(new WxMpDraftCoverInfo.CropPercent("1_1", "0.3", "0", "1", "0.7"));
+
+    WxMpDraftArticles draftArticle = WxMpDraftArticles.builder()
+      .articleType(WxConsts.ArticleType.NEWS_PIC)
+      .title("修改图片草稿")
+      .content("修改后的图片消息的具体内容")
+      // 打开评论、所有人可评论
+      .needOpenComment(1).onlyFansCanComment(0)
+      .imageInfo(WxMpDraftImageInfo.builder().imageList(imageItems).build())
+      .coverInfo(WxMpDraftCoverInfo.builder().cropPercentList(cropPercents).build())
+      .productInfo(WxMpDraftProductInfo.builder().footerProductInfo(new WxMpDraftProductInfo.FooterProductInfo("")).build())
+      .build();
+
+    WxMpUpdateDraft updateDraft = WxMpUpdateDraft.builder()
+      .mediaId(mediaId)
+      .index(0)
+      .articles(draftArticle)
+      .build();
+    Boolean updateDraftResult = this.wxService.getDraftService().updateDraft(updateDraft);
+    assertThat(updateDraftResult).isTrue();
+  }
+
+  @Test
+  public void testDelDraftPic() throws WxErrorException {
+    Boolean delDraftResult = this.wxService.getDraftService().delDraft(mediaId);
+    System.out.println(delDraftResult);
+    // 【响应数据】：{"errcode":0,"errmsg":"ok"}
+    assertThat(delDraftResult).isTrue();
+  }
+
 }
 
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMapConfigImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMapConfigImplTest.java
new file mode 100644
index 0000000000..167c0e019c
--- /dev/null
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMapConfigImplTest.java
@@ -0,0 +1,58 @@
+package me.chanjar.weixin.mp.api.impl;
+
+import com.google.inject.Inject;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.api.test.ApiTestModule;
+import me.chanjar.weixin.mp.config.impl.WxMpMapConfigImpl;
+import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+import static org.testng.Assert.assertEquals;
+
+/**
+ * 测试 ConcurrentHashMap 保存配置信息
+ * @author jimmyjimmy-sw
+ */
+@Test
+@Guice(modules = ApiTestModule.class)
+public class WxMpMapConfigImplTest {
+
+  @Inject
+  private WxMpService wxService;
+
+  /**
+   * 测试多租户保存 WxMpMapConfigImpl 到 WxMpService，切换之后能获取到租户各自AppId对应的token
+   * @throws WxErrorException
+   */
+  @Test
+  public void testAppidSwitch() throws WxErrorException {
+    // 保存租户A的配置信息，并获取token
+    WxMpMapConfigImpl configAppA = new WxMpMapConfigImpl();
+    String appidA = "APPID_A";
+    configAppA.setAppId(appidA);
+    configAppA.setSecret("APP_SECRET_A");
+    configAppA.useStableAccessToken(true);
+    String tokenA = "TOKEN_A";
+    configAppA.updateAccessToken(tokenA,60 * 60 * 1);
+    wxService.addConfigStorage(appidA, configAppA);
+    WxMpConfigStorageHolder.set(appidA);
+    assertEquals(this.wxService.getAccessToken(),tokenA);
+
+    // 保存租户B的配置信息，并获取token
+    WxMpMapConfigImpl configAppB = new WxMpMapConfigImpl();
+    String appidB = "APPID_B";
+    configAppB.setAppId(appidB);
+    configAppB.setSecret("APP_SECRET_B");
+    configAppB.useStableAccessToken(true);
+    String tokenB = "TOKEN_B";
+    configAppB.updateAccessToken(tokenB,60 * 60 * 1);
+    wxService.addConfigStorage(appidB, configAppB);
+    WxMpConfigStorageHolder.set(appidB);
+    assertEquals(this.wxService.getAccessToken(),tokenB);
+
+    // 上下文切换到租户A 获取租户A的token
+    WxMpConfigStorageHolder.set(appidA);
+    assertEquals(this.wxService.getAccessToken(),tokenA);
+  }
+}
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java
index 707f1df311..8068a5a302 100644
--- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpMaterialServiceImplTest.java
@@ -135,11 +135,6 @@ public void testAddNews() throws WxErrorException {
 
     wxMpMaterialNewsMultiple.addArticle(article1);
     wxMpMaterialNewsMultiple.addArticle(article2);
-
-    WxMpMaterialUploadResult resSingle = this.wxService.getMaterialService().materialNewsUpload(wxMpMaterialNewsSingle);
-    this.singleNewsMediaId = resSingle.getMediaId();
-    WxMpMaterialUploadResult resMulti = this.wxService.getMaterialService().materialNewsUpload(wxMpMaterialNewsMultiple);
-    this.multiNewsMediaId = resMulti.getMediaId();
   }
 
   @Test(dependsOnMethods = {"testAddNews"})
@@ -201,8 +196,6 @@ public void testUpdateNewsInfo() throws WxErrorException {
     wxMpMaterialArticleUpdateSingle.setMediaId(this.singleNewsMediaId);
     wxMpMaterialArticleUpdateSingle.setArticles(articleSingle);
     wxMpMaterialArticleUpdateSingle.setIndex(0);
-    boolean resultSingle = this.wxService.getMaterialService().materialNewsUpdate(wxMpMaterialArticleUpdateSingle);
-    assertTrue(resultSingle);
     wxMpMaterialNewsSingle = this.wxService.getMaterialService()
       .materialNewsInfo(this.singleNewsMediaId);
     assertNotNull(wxMpMaterialNewsSingle);
@@ -218,8 +211,6 @@ public void testUpdateNewsInfo() throws WxErrorException {
     wxMpMaterialArticleUpdateMulti.setMediaId(this.multiNewsMediaId);
     wxMpMaterialArticleUpdateMulti.setArticles(articleMulti);
     wxMpMaterialArticleUpdateMulti.setIndex(1);
-    boolean resultMulti = this.wxService.getMaterialService().materialNewsUpdate(wxMpMaterialArticleUpdateMulti);
-    assertTrue(resultMulti);
     wxMpMaterialNewsMultiple = this.wxService.getMaterialService()
       .materialNewsInfo(this.multiNewsMediaId);
     assertNotNull(wxMpMaterialNewsMultiple);
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java
index 636bedb855..f569c09d9d 100644
--- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpServiceImplTest.java
@@ -44,6 +44,15 @@ public void testBuildQrConnectUrl() {
     System.out.println(qrConnectUrl);
   }
 
+  @Test
+  public void testBuildQrConnectRedirectUrl() {
+    String qrConnectRedirectUrl = this.wxService.getWxMpConfigStorage().getQrConnectRedirectUrl();
+    String qrConnectUrl = this.wxService.buildQrConnectUrl(qrConnectRedirectUrl,
+      WxConsts.QrConnectScope.SNSAPI_LOGIN, null);
+    Assert.assertNotNull(qrConnectUrl);
+    System.out.println(qrConnectUrl);
+  }
+
   public void testGetTicket() throws WxErrorException {
     String ticket = this.wxService.getTicket(TicketType.SDK, false);
     System.out.println(ticket);
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/subscribe/WxMpSubscribeMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/subscribe/WxMpSubscribeMessageTest.java
index 078ad51570..684211659f 100644
--- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/subscribe/WxMpSubscribeMessageTest.java
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/subscribe/WxMpSubscribeMessageTest.java
@@ -2,6 +2,9 @@
 
 import org.testng.annotations.*;
 
+import java.io.Serializable;
+import java.util.Arrays;
+
 import static org.testng.AssertJUnit.*;
 
 /**
@@ -43,4 +46,9 @@ public void testToJson() {
     assertEquals(message.toJson(), actual);
 
   }
+
+  @Test
+  void testWxMpSubscribeMessageIsSerializable() {
+    assertTrue(Arrays.stream(WxMpSubscribeMessage.class.getInterfaces()).anyMatch(anInterface -> anInterface.isInstance(Serializable.class)));
+  }
 }
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateMessageTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateMessageTest.java
index fa7cd92967..5012be59a8 100644
--- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateMessageTest.java
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/bean/template/WxMpTemplateMessageTest.java
@@ -17,7 +17,7 @@ public void testToJson() {
     WxMpTemplateMessage tm = WxMpTemplateMessage.builder()
       .toUser("OPENID")
       .templateId("ngqIpbwh8bUfcSsECmogfXcV14J0tQlEpBO27izEYtY")
-      .miniProgram(new WxMpTemplateMessage.MiniProgram("xiaochengxuappid12345", "index?foo=bar",true))
+      .miniProgram(new WxMpTemplateMessage.MiniProgram("xiaochengxuappid12345", "index?foo=bar", true))
       .url("http://weixin.qq.com/download")
       .clientMsgId("MSG_000001")
       .build();
@@ -26,7 +26,29 @@ public void testToJson() {
       new WxMpTemplateData("first", "haahah", "#FF00FF"));
     tm.addData(
       new WxMpTemplateData("remark", "heihei", "#FF00FF"));
-    assertEquals(tm.toJson(), "{\"touser\":\"OPENID\",\"template_id\":\"ngqIpbwh8bUfcSsECmogfXcV14J0tQlEpBO27izEYtY\",\"client_msg_id\":\"MSG_000001\",\"url\":\"http://weixin.qq.com/download\",\"miniprogram\":{\"appid\":\"xiaochengxuappid12345\",\"path\":\"index?foo=bar\"},\"data\":{\"first\":{\"value\":\"haahah\",\"color\":\"#FF00FF\"},\"remark\":{\"value\":\"heihei\",\"color\":\"#FF00FF\"}}}");
+
+    assertEquals("{\"touser\":\"OPENID\",\"template_id\":\"ngqIpbwh8bUfcSsECmogfXcV14J0tQlEpBO27izEYtY\",\"client_msg_id\":\"MSG_000001\",\"url\":\"http://weixin.qq.com/download\",\"miniprogram\":{\"appid\":\"xiaochengxuappid12345\",\"path\":\"index?foo=bar\"},\"data\":{\"first\":{\"value\":\"haahah\",\"color\":\"#FF00FF\"},\"remark\":{\"value\":\"heihei\",\"color\":\"#FF00FF\"}}}", tm.toJson());
   }
 
+  @Test
+  public void testAddData() {
+    WxMpTemplateMessage tm = WxMpTemplateMessage.builder().build()
+      .addData(new WxMpTemplateData("thing01", "张三李四王麻子张三李四王麻子张三李四王麻子张三李四王麻子"))
+      .addData(new WxMpTemplateData("time01", "2019年10月1日 15:01"))
+      .addData(new WxMpTemplateData("character_string01", "1234567890123456789012345678901234567890"))
+      .addData(new WxMpTemplateData("amount01", "￥100.21"))
+      .addData(new WxMpTemplateData("phone_number01", "+86-0766-668888661111"))
+      .addData(new WxMpTemplateData("car_number01", "粤A8Z888挂9"))
+      .addData(new WxMpTemplateData("const01", "支付状态、排队状态、天气状态、物流状态、用药提醒、还款提醒"));
+
+    assertEquals(7, tm.getData().size());
+
+    assertEquals("张三李四王麻子张三李四王麻子张三李...", tm.getData().get(0).getValue());
+    assertEquals("2019年10月1日 15:01", tm.getData().get(1).getValue());
+    assertEquals("12345678901234567890123456789...", tm.getData().get(2).getValue());
+    assertEquals("￥100.21", tm.getData().get(3).getValue());
+    assertEquals("+86-0766-66888...", tm.getData().get(4).getValue());
+    assertEquals("粤A8Z8...", tm.getData().get(5).getValue());
+    assertEquals("支付状态、排队状态、天气状态、物流...", tm.getData().get(6).getValue());
+  }
 }
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/DemoOAuth2Handler.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/DemoOAuth2Handler.java
index ce23512e29..3d257b873e 100644
--- a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/DemoOAuth2Handler.java
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/demo/DemoOAuth2Handler.java
@@ -18,7 +18,7 @@ public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
                                   Map<String, Object> context, WxMpService wxMpService,
                                   WxSessionManager sessionManager) {
     String href = "<a href=\"" + wxMpService.getOAuth2Service().buildAuthorizationUrl(
-      wxMpService.getWxMpConfigStorage().getOauth2redirectUri(),
+      wxMpService.getWxMpConfigStorage().getOauth2RedirectUrl(),
       WxConsts.OAuth2Scope.SNSAPI_USERINFO, null) + "\">测试oauth2</a>";
     return WxMpXmlOutMessage.TEXT().content(href)
       .fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
diff --git a/weixin-java-mp/src/test/resources/test-config.sample.xml b/weixin-java-mp/src/test/resources/test-config.sample.xml
index 3df1de9d57..003fa8565c 100644
--- a/weixin-java-mp/src/test/resources/test-config.sample.xml
+++ b/weixin-java-mp/src/test/resources/test-config.sample.xml
@@ -10,7 +10,7 @@
   <partnerKey>商户平台设置的API密钥</partnerKey>
   <keyPath>商户平台的证书文件地址</keyPath>
   <templateId>模版消息的模版ID</templateId>
-  <oauth2redirectUri>网页授权获取用户信息回调地址</oauth2redirectUri>
-  <qrconnectRedirectUrl>网页应用授权登陆回调地址</qrconnectRedirectUrl>
+  <oauth2RedirectUrl>网页授权获取用户信息回调地址</oauth2RedirectUrl>
+  <qrConnectRedirectUrl>网页应用授权登陆回调地址</qrConnectRedirectUrl>
   <kfAccount>完整客服账号，格式为：账号前缀@公众号微信号</kfAccount>
 </xml>
diff --git a/weixin-java-open/pom.xml b/weixin-java-open/pom.xml
index e33502b6d0..74466d8ebf 100644
--- a/weixin-java-open/pom.xml
+++ b/weixin-java-open/pom.xml
@@ -7,7 +7,7 @@
   <parent>
     <groupId>com.github.binarywang</groupId>
     <artifactId>wx-java</artifactId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
 
   <artifactId>weixin-java-open</artifactId>
@@ -48,6 +48,11 @@
       <artifactId>okhttp</artifactId>
       <scope>provided</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.httpcomponents.client5</groupId>
+      <artifactId>httpclient5</artifactId>
+      <scope>provided</scope>
+    </dependency>
 
     <dependency>
       <groupId>org.testng</groupId>
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaAuthAndIcpService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaAuthAndIcpService.java
new file mode 100644
index 0000000000..de2c0a0de2
--- /dev/null
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaAuthAndIcpService.java
@@ -0,0 +1,32 @@
+package me.chanjar.weixin.open.api;
+
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.open.bean.authandicp.WxOpenQueryAuthAndIcpResult;
+import me.chanjar.weixin.open.bean.authandicp.WxOpenSubmitAuthAndIcpParam;
+import me.chanjar.weixin.open.bean.authandicp.WxOpenSubmitAuthAndIcpResult;
+
+/**
+ * 微信第三方平台 小程序认证及备案
+ * @author 痴货
+ * @createTime 2025/06/18 23:00
+ */
+public interface WxOpenMaAuthAndIcpService {
+
+  String QUERY_AUTH_AND_ICP = "https://api.weixin.qq.com/wxa/sec/query_auth_and_icp";
+
+  String SUBMIT_AUTH_AND_ICP = "https://api.weixin.qq.com/wxa/sec/submit_auth_and_icp";
+
+  /**
+   * 查询小程序认证及备案进度。
+   * @param procedureId 小程序认证及备案任务流程id
+   * @return 小程序认证及备案进度
+   */
+  WxOpenQueryAuthAndIcpResult queryAuthAndIcp(String procedureId) throws WxErrorException;
+
+  /**
+   * 提交小程序认证及备案信息。
+   * @param param 提交小程序认证及备案信息参数
+   * @return 提交结果
+   */
+  WxOpenSubmitAuthAndIcpResult submitAuthAndIcp(WxOpenSubmitAuthAndIcpParam param) throws WxErrorException;
+}
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaBasicService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaBasicService.java
index cae5faa783..3952f7dbf9 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaBasicService.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaBasicService.java
@@ -2,9 +2,9 @@
 
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.open.bean.ma.WxFastMaCategory;
-import me.chanjar.weixin.open.bean.ma.WxOpenMaApplyOrderPathInfo;
 import me.chanjar.weixin.open.bean.result.*;
 
+import java.io.UnsupportedEncodingException;
 import java.util.List;
 
 /**
@@ -54,19 +54,23 @@ public interface WxOpenMaBasicService {
    */
   String OPEN_GET_ALL_CATEGORIES = "https://api.weixin.qq.com/cgi-bin/wxopen/getallcategories";
   /**
-   * 8.2 添加类目
+   * 8.2 获取不同类型主体可设置的类目
+   */
+  String OPEN_GET_ALL_CATEGORIES_BY_TYPE = "https://api.weixin.qq.com/cgi-bin/wxopen/getcategoriesbytype";
+  /**
+   * 8.3 添加类目
    */
   String OPEN_ADD_CATEGORY = "https://api.weixin.qq.com/cgi-bin/wxopen/addcategory";
   /**
-   * 8.3 删除类目
+   * 8.4 删除类目
    */
   String OPEN_DELETE_CATEGORY = "https://api.weixin.qq.com/cgi-bin/wxopen/deletecategory";
   /**
-   * 8.4 获取账号已经设置的所有类目
+   * 8.5 获取账号已经设置的所有类目
    */
   String OPEN_GET_CATEGORY = "https://api.weixin.qq.com/cgi-bin/wxopen/getcategory";
   /**
-   * 8.5 修改类目
+   * 8.6 修改类目
    */
   String OPEN_MODIFY_CATEGORY = "https://api.weixin.qq.com/cgi-bin/wxopen/modifycategory";
 
@@ -75,6 +79,8 @@ public interface WxOpenMaBasicService {
    */
   String OPEN_GET_ORDER_PATH_INFO = "https://api.weixin.qq.com/wxa/security/getorderpathinfo";
 
+  String URL_COMPONENT_REBIND_ADMIN = "https://mp.weixin.qq.com/wxopen/componentrebindadmin?appid=%s&component_appid=%s&redirect_uri=%s";
+
 
   /**
    * 1.获取小程序的信息
@@ -145,6 +151,14 @@ WxFastMaSetNickameResult setNickname(String nickname, String idCard, String lice
    */
   WxOpenResult modifySignature(String signature) throws WxErrorException;
 
+  /**
+   * 7.1 获取换绑管理员URL
+   * @param redirectUri 跳转URL
+   * @param appId 公众号的 appid
+   * @return 换绑管理员URL
+   */
+  String getComponentRebindAdminUrl(String redirectUri, String appId) throws UnsupportedEncodingException;
+
   /**
    * 7.3 管理员换绑
    *
@@ -168,7 +182,12 @@ WxFastMaSetNickameResult setNickname(String nickname, String idCard, String lice
   String getAllCategories() throws WxErrorException;
 
   /**
-   * 8.2添加类目
+   * 8.2获取不同类型主体可设置的类目
+   */
+  WxOpenGetAllCategoriesByTypeResult getAllCategoriesByType(String verifyType) throws WxErrorException;
+
+  /**
+   * 8.3添加类目
    *
    * @param categoryList 类目列表
    * @return .
@@ -177,7 +196,7 @@ WxFastMaSetNickameResult setNickname(String nickname, String idCard, String lice
   WxOpenResult addCategory(List<WxFastMaCategory> categoryList) throws WxErrorException;
 
   /**
-   * 8.3删除类目
+   * 8.4删除类目
    *
    * @param first  一级类目ID
    * @param second 二级类目ID
@@ -187,7 +206,7 @@ WxFastMaSetNickameResult setNickname(String nickname, String idCard, String lice
   WxOpenResult deleteCategory(int first, int second) throws WxErrorException;
 
   /**
-   * 8.4获取账号已经设置的所有类目
+   * 8.5获取账号已经设置的所有类目
    *
    * @return .
    * @throws WxErrorException .
@@ -195,7 +214,7 @@ WxFastMaSetNickameResult setNickname(String nickname, String idCard, String lice
   WxFastMaBeenSetCategoryResult getCategory() throws WxErrorException;
 
   /**
-   * 8.5修改类目
+   * 8.6修改类目
    *
    * @param category 实体
    * @return .
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaEmbeddedService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaEmbeddedService.java
new file mode 100644
index 0000000000..80fdac2f38
--- /dev/null
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaEmbeddedService.java
@@ -0,0 +1,133 @@
+package me.chanjar.weixin.open.api;
+
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.open.bean.result.WxOpenMaEmbeddedListResult;
+
+/**
+ * 半屏小程序管理服务
+ * <pre>
+ *   <a href="https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/embedded-management/addEmbedded.html">半屏小程序管理</a>
+ * </pre>
+ *
+ * @author Yuan
+ * @version 1.0.0
+ * @date 2024-12-04 16:55:19
+ */
+public interface WxOpenMaEmbeddedService {
+
+  /**
+   * 添加半屏小程序
+   * <pre>
+   *     本接口用于添加半屏小程序
+   * </pre>
+   */
+  String API_ADD_EMBEDDED = "https://api.weixin.qq.com/wxaapi/wxaembedded/add_embedded";
+
+  /**
+   * 删除半屏小程序
+   * <pre>
+   *     用本接口可以删除已经获得授权调用的半屏小程序
+   *     说明：通过add_embedded接口添加半屏小程序后，可通过当前接口删除已经添加到半屏小程序列表的小程序
+   * </pre>
+   */
+  String API_DELETE_EMBEDDED = "https://api.weixin.qq.com/wxaapi/wxaembedded/del_embedded";
+
+  /**
+   * 获取半屏小程序调用列表
+   * <pre>
+   *     调用本接口可以获取半屏小程序调用列表
+   *     说明：通过addEmbedded接口添加半屏小程序后，可通过当前接口获取半屏小程序调用列表
+   * </pre>
+   */
+  String API_GET_EMBEDDED_LIST = "https://api.weixin.qq.com/wxaapi/wxaembedded/get_list";
+
+  /**
+   * 取消授权小程序
+   * <pre>
+   *     调用本接口可以取消已经授权的小程序
+   *     说明：可通过get_own_list接口获取当前半屏小程序已经授权的小程序列表，可通过当前接口取消对某个小程序的调用权限
+   * </pre>
+   */
+  String API_DELETE_AUTHORIZED_EMBEDDED = "https://api.weixin.qq.com/wxaapi/wxaembedded/del_authorize";
+
+  /**
+   * 获取半屏小程序授权列表
+   * <pre>
+   *     调用本接口可以获取半屏小程序授权列表
+   *     说明：一个半屏小程序可授权给1000个小程序调用，通过该接口可获取已经授权的小程序列表
+   * </pre>
+   */
+  String API_GET_OWN_LIST = "https://api.weixin.qq.com/wxaapi/wxaembedded/get_own_list";
+
+  /**
+   * 设置授权方式
+   */
+  String API_SET_AUTHORIZED_EMBEDDED = "https://api.weixin.qq.com/wxaapi/wxaembedded/set_authorize";
+
+  /**
+   * 添加半屏小程序
+   *
+   * @param embeddedAppId 半屏小程序appId
+   * @param applyReason   申请理由
+   * @author Yuan
+   * @date 2024-12-04 17:33:33
+   */
+  void addEmbedded(String embeddedAppId, String applyReason) throws WxErrorException;
+
+  /**
+   * 删除半屏小程序
+   *
+   * @param embeddedAppId 半屏小程序appId
+   * @author Yuan
+   * @date 2024-12-04 17:33:33
+   */
+  void deleteEmbedded(String embeddedAppId) throws WxErrorException;
+
+  /**
+   * 获取半屏小程序调用列表
+   *
+   * @return {@link WxOpenMaEmbeddedListResult }
+   * @author Yuan
+   * @date 2024-12-04 17:33:33
+   */
+  WxOpenMaEmbeddedListResult getEmbeddedList() throws WxErrorException;
+
+  /**
+   * 取消授权小程序
+   *
+   * @param embeddedAppId 半屏小程序appId
+   * @author Yuan
+   * @date 2024-12-04 17:33:33
+   */
+  void deleteAuthorizedEmbedded(String embeddedAppId) throws WxErrorException;
+
+  /**
+   * 获取半屏小程序授权列表,默认分页起始值为0，一次拉取最大值为1000
+   *
+   * @return {@link WxOpenMaEmbeddedListResult }
+   * @author Yuan
+   * @date 2024-12-04 17:33:33
+   */
+  WxOpenMaEmbeddedListResult getOwnList() throws WxErrorException;
+
+  /**
+   * 获取半屏小程序授权列表
+   *
+   * @param start 分页起始值 ，默认值为0
+   * @param num   一次拉取最大值，最大 1000，默认值为10
+   * @return {@link WxOpenMaEmbeddedListResult }
+   * @author Yuan
+   * @date 2024-12-04 17:33:33
+   */
+  WxOpenMaEmbeddedListResult getOwnList(Integer start, Integer num) throws WxErrorException;
+
+  /**
+   * 设置授权方式
+   *
+   * @param flag 半屏小程序授权方式。0表示需要管理员验证；1表示自动通过；2表示自动拒绝。
+   * @author Yuan
+   * @date 2024-12-04 17:33:33
+   */
+  void setAuthorizedEmbedded(Integer flag) throws WxErrorException;
+
+}
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaIcpService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaIcpService.java
index ad59b246c7..8176ea0231 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaIcpService.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaIcpService.java
@@ -97,6 +97,19 @@ public interface WxOpenMaIcpService {
    */
   String GET_ICP_MEDIA = "https://api.weixin.qq.com/wxa/icp/get_icp_media";
 
+  /**
+   * 申请小程序认证及备案
+   * https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/wxverifyicp/submitAuthAndIcp.html
+   */
+  String SUBMIT_AUTH_AND_ICP = "https://api.weixin.qq.com/wxa/sec/submit_auth_and_icp";
+
+  /**
+   * 查询小程序认证及备案进度
+   * https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/wxverifyicp/queryAuthAndIcp.html
+   */
+  String QUERY_AUTH_AND_ICP = "https://api.weixin.qq.com/wxa/sec/query_auth_and_icp";
+
+
   /**
    * 查询人脸核身任务状态
    *
@@ -109,10 +122,11 @@ public interface WxOpenMaIcpService {
   /**
    * 发起小程序管理员人脸核身
    *
+   * @param alongWithAuth 小程序认证及备案二合一场景，填 true，否则为小程序备案场景。默认值为 false。
    * @return 人脸核验任务结果
    * @throws WxErrorException e
    */
-  WxOpenIcpCreateIcpVerifyTaskResult createIcpVerifyTask() throws WxErrorException;
+  WxOpenIcpCreateIcpVerifyTaskResult createIcpVerifyTask(boolean alongWithAuth) throws WxErrorException;
 
   /**
    * 上传小程序备案媒体材料
@@ -204,4 +218,5 @@ public interface WxOpenMaIcpService {
    * @throws WxErrorException e
    */
   File getIcpMedia(String mediaId) throws WxErrorException;
+
 }
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java
index 6d540940c0..fef85d7f2e 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenMaService.java
@@ -731,6 +731,13 @@ WxOpenMaDomainResult modifyDomain(String action, List<String> requestDomains, Li
    */
   WxOpenMaIcpService getIcpService();
 
+  /**
+   * 小程序认证及备案服务
+   *
+   * @return 小程序认证及备案服务
+   */
+  WxOpenMaAuthAndIcpService getAuthAndIcpService();
+
   /**
    * 小程序用户隐私保护指引服务
    *
@@ -738,6 +745,15 @@ WxOpenMaDomainResult modifyDomain(String action, List<String> requestDomains, Li
    */
   WxOpenMaPrivacyService getPrivacyService();
 
+  /**
+   * 半屏小程序服务
+   *
+   * @return {@link WxOpenMaEmbeddedService }
+   * @author Yuan
+   * @date 2024-12-04 18:42:21
+   */
+  WxOpenMaEmbeddedService getEmbeddedService();
+
   /**
    * 购物订单
    *
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenService.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenService.java
index 2305be311b..f9806d2c9e 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenService.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/WxOpenService.java
@@ -1,6 +1,5 @@
 package me.chanjar.weixin.open.api;
 
-import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
 import me.chanjar.weixin.common.bean.result.WxMinishopImageUploadResult;
 import me.chanjar.weixin.common.error.WxErrorException;
 
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenComponentServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenComponentServiceImpl.java
index 1c0e7f16f6..80da912bef 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenComponentServiceImpl.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenComponentServiceImpl.java
@@ -150,7 +150,7 @@ public boolean checkSignature(String timestamp, String nonce, String signature)
       return SHA1.gen(getWxOpenConfigStorage().getComponentToken(), 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;
     }
   }
@@ -705,7 +705,7 @@ public String checkAuditStatus(String wxName) throws WxErrorException {
     jsonObject.addProperty("wx_name", wxName);
     String url = CHECK_SHOP_AUDITSTATUS_URL + "?access_token=" + getComponentAccessToken(false);
     String response = post(url, jsonObject.toString());
-    log.info("CHECK_SHOP_AUDITSTATUS_URL: " + response);
+    log.info("CHECK_SHOP_AUDITSTATUS_URL: {}", response);
     return response;
   }
 
@@ -715,7 +715,7 @@ public String checkAuditStatus(String appId, String wxName) throws WxErrorExcept
     jsonObject.addProperty("wx_name", wxName);
     String url = CHECK_SHOP_AUDITSTATUS_URL + "?access_token=" + getAuthorizerAccessToken(appId, false);
     String response = post(url, jsonObject.toString());
-    log.info("CHECK_SHOP_AUDITSTATUS_URL: " + response);
+    log.info("CHECK_SHOP_AUDITSTATUS_URL: {}", response);
     return response;
   }
 
@@ -757,7 +757,7 @@ public WxOpenResult submitBasicInfo(String appId, MinishopNameInfo nameInfo, Min
   @Override
   public WxMinishopImageUploadResult uploadMinishopImagePicFile(String appId, Integer height, Integer width, File file) throws WxErrorException {
     String url = WxOpenMinishopService.UPLOAD_IMG_MINISHOP_FILE_URL + "?access_token=" + getAuthorizerAccessToken(appId, false) + "&height=" + height + "&width=" + width;
-    log.info("upload url: " + url);
+    log.info("upload url: {}", url);
 //    String response = (url, file);
     WxMinishopImageUploadResult result = getWxOpenService().uploadMinishopMediaFile(url, file);
 
@@ -770,13 +770,13 @@ public MinishopCategories getMinishopCategories(String appId, Integer fCatId) th
     jsonObject.addProperty("f_cat_id", fCatId);
     String url = MINISHOP_CATEGORY_GET_URL + "?access_token=" + getAuthorizerAccessToken(appId, false);
     String response = getWxOpenService().post(url, jsonObject.toString());
-    log.info("response: " + response);
+    log.info("response: {}", response);
     JsonObject respJson = GsonParser.parse(response);
     MinishopCategories categories = new MinishopCategories();
     categories.setErrcode(respJson.get(WxConsts.ERR_CODE).getAsInt());
     if (categories.getErrcode() == 0) {
       JsonArray catListJson = respJson.getAsJsonArray("cat_list");
-      if (catListJson != null || catListJson.size() > 0) {
+      if (catListJson != null || !catListJson.isEmpty()) {
         List<MinishopCategory> categoryList = new ArrayList<>();
         for (int i = 0; i < catListJson.size(); i++) {
           JsonObject catJson = catListJson.get(i).getAsJsonObject();
@@ -806,7 +806,7 @@ public MinishopBrandList getMinishopBrands(String appId) throws WxErrorException
     brandList.setErrcode(respJson.get(WxConsts.ERR_CODE).getAsInt());
     if (brandList.getErrcode() == 0) {
       JsonArray brandArrayJson = respJson.get("brands").getAsJsonArray();
-      if (brandArrayJson.size() > 0) {
+      if (!brandArrayJson.isEmpty()) {
         List<MinishopBrand> brands = new ArrayList<>();
         for (int i = 0; i < brandArrayJson.size(); i++) {
           JsonObject brandJson = brandArrayJson.get(i).getAsJsonObject();
@@ -843,7 +843,7 @@ public MinishopDeliveryTemplateResult getMinishopDeliveryTemplate(String appId)
     templateResult.setErrCode(respJson.get(WxConsts.ERR_CODE).getAsInt());
     if (templateResult.getErrCode() == 0) {
       JsonArray templateArrayJson = respJson.get("template_list").getAsJsonArray();
-      if (templateArrayJson.size() > 0) {
+      if (!templateArrayJson.isEmpty()) {
         List<MinishopDeliveryTemplate> templateList = new ArrayList<>();
         for (int i = 0; i < templateArrayJson.size(); i++) {
           JsonObject templateJson = templateArrayJson.get(i).getAsJsonObject();
@@ -876,7 +876,7 @@ public MinishopShopCatList getMinishopCatList(String appId) throws WxErrorExcept
     shopCatList.setErrcode(respJson.get(WxConsts.ERR_CODE).getAsInt());
     if (shopCatList.getErrcode() == 0) {
       JsonArray shopcatArrayJson = respJson.get("shopcat_list").getAsJsonArray();
-      if (shopcatArrayJson.size() > 0) {
+      if (!shopcatArrayJson.isEmpty()) {
         List<MinishopShopCat> shopCats = new ArrayList<>();
         for (int i = 0; i < shopcatArrayJson.size(); i++) {
           JsonObject shopCatJson = shopcatArrayJson.get(i).getAsJsonObject();
@@ -906,7 +906,7 @@ public WxMinishopAddGoodsSpuResult<List<WxMinishopDeliveryCompany>> getMinishopD
     String response = getWxOpenService().post(url, jsonObject.toString());
 
     JsonObject respObj = GsonParser.parse(response);
-    WxMinishopAddGoodsSpuResult result = new WxMinishopAddGoodsSpuResult();
+    WxMinishopAddGoodsSpuResult<List<WxMinishopDeliveryCompany>> result = new WxMinishopAddGoodsSpuResult<>();
     result.setErrcode(respObj.get(WxConsts.ERR_CODE).getAsInt());
     if (result.getErrcode() == 0) {
       JsonArray companyArray = respObj.get("company_list").getAsJsonArray();
@@ -931,7 +931,7 @@ public Integer minishopCreateCoupon(String appId, WxMinishopCoupon couponInfo) t
     JsonObject jsonObject = couponInfo.toJsonObject();
     String response = getWxOpenService().post(url, jsonObject.toString());
     JsonObject respJson = GsonParser.parse(response);
-    Integer couponId = -1;
+    int couponId = -1;
     if (respJson.get(WxConsts.ERR_CODE).getAsInt() == 0) {
       JsonObject dataJson = respJson.get("data").getAsJsonObject();
       couponId = dataJson.get("coupon_id").getAsInt();
@@ -965,7 +965,7 @@ public Integer minishopUpdateCoupon(String appId, WxMinishopCoupon couponInfo) t
     JsonObject jsonObject = couponInfo.toJsonObject();
     String response = getWxOpenService().post(url, jsonObject.toString());
     JsonObject respJson = GsonParser.parse(response);
-    Integer couponId = -1;
+    int couponId = -1;
     if (respJson.get(WxConsts.ERR_CODE).getAsInt() == 0) {
       JsonObject dataJson = respJson.get("data").getAsJsonObject();
       couponId = dataJson.get("coupon_id").getAsInt();
@@ -994,7 +994,7 @@ public WxMinishopAddGoodsSpuResult<WxMinishopAddGoodsSpuData> minishopGoodsAddSp
     String response = getWxOpenService().post(url, jsonObject.toString());
 
     JsonObject respObj = GsonParser.parse(response);
-    WxMinishopAddGoodsSpuResult result = new WxMinishopAddGoodsSpuResult();
+    WxMinishopAddGoodsSpuResult<WxMinishopAddGoodsSpuData> result = new WxMinishopAddGoodsSpuResult<>();
     result.setErrcode(respObj.get(WxConsts.ERR_CODE).getAsInt());
 
     if (result.getErrcode() == 0) {
@@ -1032,7 +1032,7 @@ public WxMinishopAddGoodsSpuResult<WxMinishopAddGoodsSpuData> minishopGoodsUpdat
     String response = getWxOpenService().post(url, jsonObject.toString());
 
     JsonObject respObj = GsonParser.parse(response);
-    WxMinishopAddGoodsSpuResult result = new WxMinishopAddGoodsSpuResult();
+    WxMinishopAddGoodsSpuResult<WxMinishopAddGoodsSpuData> result = new WxMinishopAddGoodsSpuResult<>();
     result.setErrcode(respObj.get(WxConsts.ERR_CODE).getAsInt());
     if (result.getErrcode() == 0) {
       JsonObject dataObj = respObj.get("data").getAsJsonObject();
@@ -1082,7 +1082,7 @@ public WxMinishopAddGoodsSpuResult<WxMinishopAddGoodsSkuData> minishiopGoodsAddS
     String response = getWxOpenService().post(url, jsonObject.toString());
 
     JsonObject respObj = GsonParser.parse(response);
-    WxMinishopAddGoodsSpuResult result = new WxMinishopAddGoodsSpuResult();
+    WxMinishopAddGoodsSpuResult<WxMinishopAddGoodsSkuData> result = new WxMinishopAddGoodsSpuResult<>();
     result.setErrcode(respObj.get(WxConsts.ERR_CODE).getAsInt());
     if (result.getErrcode() == 0) {
       JsonObject dataObj = respObj.get("data").getAsJsonObject();
@@ -1187,7 +1187,7 @@ public Integer addLimitDiscountGoods(String appId, LimitDiscountGoods limitDisco
     JsonObject jsonObject = limitDiscountGoods.toJsonObject();
     String response = getWxOpenService().post(url, jsonObject.toString());
     JsonObject respObj = GsonParser.parse(response);
-    Integer taskId = 0;
+    int taskId = 0;
     if (respObj.get(WxConsts.ERR_CODE).getAsInt() == 0) {
       taskId = respObj.get("task_id").getAsInt();
     }
@@ -1208,7 +1208,7 @@ public List<LimitDiscountGoods> getLimitDiscountList(String appId, Integer statu
       //成功获取到秒杀活动列表
 
       JsonArray jsonArray = respObj.get("limited_discount_list").getAsJsonArray();
-      if (jsonArray != null && jsonArray.size() > 0) {
+      if (jsonArray != null && !jsonArray.isEmpty()) {
         for (int i = 0; i < jsonArray.size(); i++) {
           JsonObject goodsObj = jsonArray.get(i).getAsJsonObject();
           LimitDiscountGoods discountGoods = new LimitDiscountGoods();
@@ -1219,12 +1219,12 @@ public List<LimitDiscountGoods> getLimitDiscountList(String appId, Integer statu
 
           List<LimitDiscountSku> skuList = new ArrayList<>();
           JsonArray skuArray = goodsObj.get("limited_discount_sku_list").getAsJsonArray();
-          if (skuArray != null && skuArray.size() > 0) {
+          if (skuArray != null && !skuArray.isEmpty()) {
             for (int j = 0; j < skuArray.size(); j++) {
               JsonObject skuObj = skuArray.get(i).getAsJsonObject();
               LimitDiscountSku sku = new LimitDiscountSku();
               sku.setSkuId(skuObj.get("sku_id").getAsLong());
-              sku.setSalePrice(new BigDecimal(skuObj.get("sale_price").getAsDouble() / 100));
+              sku.setSalePrice(BigDecimal.valueOf(skuObj.get("sale_price").getAsDouble() / 100));
               sku.setSaleStock(skuObj.get("sale_stock").getAsInt());
               skuList.add(sku);
             }
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenFastMaServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenFastMaServiceImpl.java
index 911488ffae..84ff7b495c 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenFastMaServiceImpl.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenFastMaServiceImpl.java
@@ -8,10 +8,10 @@
 import me.chanjar.weixin.open.api.WxOpenComponentService;
 import me.chanjar.weixin.open.api.WxOpenFastMaService;
 import me.chanjar.weixin.open.bean.ma.WxFastMaCategory;
-import me.chanjar.weixin.open.bean.ma.WxOpenMaApplyOrderPathInfo;
 import me.chanjar.weixin.open.bean.result.*;
 import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder;
 
+import java.io.UnsupportedEncodingException;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -100,6 +100,11 @@ public WxOpenResult modifySignature(String signature) throws WxErrorException {
     return WxOpenGsonBuilder.create().fromJson(response, WxOpenResult.class);
   }
 
+  @Override
+  public String getComponentRebindAdminUrl(String redirectUri, String appId) {
+    return "";
+  }
+
   @Override
   public WxOpenResult componentRebindAdmin(String taskid) throws WxErrorException {
     JsonObject params = new JsonObject();
@@ -113,6 +118,11 @@ public String getAllCategories() throws WxErrorException {
     return get(OPEN_GET_ALL_CATEGORIES, "");
   }
 
+  @Override
+  public WxOpenGetAllCategoriesByTypeResult getAllCategoriesByType(String verifyType)  {
+    return null;
+  }
+
   @Override
   public WxOpenResult addCategory(List<WxFastMaCategory> categoryList) throws WxErrorException {
     Map<String, Object> map = new HashMap<>();
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java
index a103315b5d..33a9b49940 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInMemoryConfigStorage.java
@@ -105,17 +105,7 @@ public Lock getComponentAccessTokenLock() {
 
   @Override
   public Lock getLockByKey(String key) {
-    Lock lock = locks.get(key);
-    if (lock == null) {
-      synchronized (this) {
-        lock = locks.get(key);
-        if (lock == null) {
-          lock = new ReentrantLock();
-          locks.put(key, lock);
-        }
-      }
-    }
-    return lock;
+    return locks.computeIfAbsent(key, e -> new ReentrantLock());
   }
 
   @Override
@@ -572,11 +562,22 @@ public String getMsgDataFormat() {
       return null;
     }
 
+    @Deprecated
     @Override
     public String getOauth2redirectUri() {
       return null;
     }
 
+    @Override
+    public String getOauth2RedirectUrl() {
+      return null;
+    }
+
+    @Override
+    public String getQrConnectRedirectUrl() {
+      return null;
+    }
+
     @Override
     public String getHttpProxyHost() {
       return this.wxOpenConfigStorage.getHttpProxyHost();
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInRedisTemplateConfigStorage.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInRedisTemplateConfigStorage.java
index 267a65c367..42034a1ffc 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInRedisTemplateConfigStorage.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenInRedisTemplateConfigStorage.java
@@ -3,11 +3,9 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Lock;
 
-import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.data.redis.core.StringRedisTemplate;
 
 import lombok.NonNull;
-import me.chanjar.weixin.common.redis.JedisWxRedisOps;
 import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps;
 import me.chanjar.weixin.common.redis.WxRedisOps;
 
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaAuthAndIcpServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaAuthAndIcpServiceImpl.java
new file mode 100644
index 0000000000..50e07d94d1
--- /dev/null
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaAuthAndIcpServiceImpl.java
@@ -0,0 +1,40 @@
+package me.chanjar.weixin.open.api.impl;
+
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.JsonObject;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.open.api.WxOpenMaAuthAndIcpService;
+import me.chanjar.weixin.open.bean.authandicp.WxOpenQueryAuthAndIcpResult;
+import me.chanjar.weixin.open.bean.authandicp.WxOpenSubmitAuthAndIcpParam;
+import me.chanjar.weixin.open.bean.authandicp.WxOpenSubmitAuthAndIcpResult;
+import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder;
+
+/**
+ * 微信第三方平台 小程序认证及备案
+ *
+ * @author 痴货
+ * @createTime 2025/06/18 23:00
+ */
+public class WxOpenMaAuthAndIcpServiceImpl implements WxOpenMaAuthAndIcpService {
+
+  private final WxMaService wxMaService;
+
+  public WxOpenMaAuthAndIcpServiceImpl(WxMaService wxMaService) {
+    this.wxMaService = wxMaService;
+  }
+
+  @Override
+  public WxOpenQueryAuthAndIcpResult queryAuthAndIcp(String procedureId) throws WxErrorException {
+    JsonObject params = new JsonObject();
+    params.addProperty("procedure_id", procedureId);
+    String response = wxMaService.post(QUERY_AUTH_AND_ICP, params);
+    return WxOpenGsonBuilder.create().fromJson(response, WxOpenQueryAuthAndIcpResult.class);
+  }
+
+  @Override
+  public WxOpenSubmitAuthAndIcpResult submitAuthAndIcp(WxOpenSubmitAuthAndIcpParam param) throws WxErrorException {
+    String response = wxMaService.post(SUBMIT_AUTH_AND_ICP, param);
+    return WxMaGsonBuilder.create().fromJson(response, WxOpenSubmitAuthAndIcpResult.class);
+  }
+}
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaBasicServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaBasicServiceImpl.java
index 943d610113..56d209a322 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaBasicServiceImpl.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaBasicServiceImpl.java
@@ -3,13 +3,16 @@
 import cn.binarywang.wx.miniapp.api.WxMaService;
 import com.google.gson.JsonArray;
 import com.google.gson.JsonObject;
+import lombok.SneakyThrows;
 import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.open.api.WxOpenComponentService;
 import me.chanjar.weixin.open.api.WxOpenMaBasicService;
 import me.chanjar.weixin.open.bean.ma.WxFastMaCategory;
-import me.chanjar.weixin.open.bean.ma.WxOpenMaApplyOrderPathInfo;
 import me.chanjar.weixin.open.bean.result.*;
 import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder;
 
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -22,9 +25,11 @@
 public class WxOpenMaBasicServiceImpl implements WxOpenMaBasicService {
 
   private final WxMaService wxMaService;
+  private final WxOpenComponentService wxOpenComponentService;
 
-  public WxOpenMaBasicServiceImpl(WxMaService wxMaService) {
+  public WxOpenMaBasicServiceImpl(WxMaService wxMaService, WxOpenComponentService wxOpenComponentService) {
     this.wxMaService = wxMaService;
+    this.wxOpenComponentService = wxOpenComponentService;
   }
 
 
@@ -82,6 +87,15 @@ public WxOpenResult modifySignature(String signature) throws WxErrorException {
     return WxOpenGsonBuilder.create().fromJson(response, WxOpenResult.class);
   }
 
+  @SneakyThrows
+  @Override
+  public String getComponentRebindAdminUrl(String redirectUri, String appId) {
+    String componentAppId = wxOpenComponentService.getWxOpenConfigStorage().getComponentAppId();
+    String encoded = URLEncoder.encode(redirectUri, "UTF-8");
+    return String.format(URL_COMPONENT_REBIND_ADMIN, appId, componentAppId, encoded);
+  }
+
+
   @Override
   public WxOpenResult componentRebindAdmin(String taskid) throws WxErrorException {
     JsonObject params = new JsonObject();
@@ -95,6 +109,14 @@ public String getAllCategories() throws WxErrorException {
     return wxMaService.get(OPEN_GET_ALL_CATEGORIES, "");
   }
 
+  @Override
+  public WxOpenGetAllCategoriesByTypeResult getAllCategoriesByType(String verifyType) throws WxErrorException {
+    JsonObject params = new JsonObject();
+    params.addProperty("verify_type", verifyType);
+    String response = wxMaService.post(OPEN_GET_ALL_CATEGORIES_BY_TYPE, params);
+    return WxOpenGsonBuilder.create().fromJson(response, WxOpenGetAllCategoriesByTypeResult.class);
+  }
+
   @Override
   public WxOpenResult addCategory(List<WxFastMaCategory> categoryList) throws WxErrorException {
     Map<String, Object> map = new HashMap<>();
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaEmbeddedServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaEmbeddedServiceImpl.java
new file mode 100644
index 0000000000..8a4a171af7
--- /dev/null
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaEmbeddedServiceImpl.java
@@ -0,0 +1,165 @@
+package me.chanjar.weixin.open.api.impl;
+
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
+import com.google.gson.JsonObject;
+import lombok.AllArgsConstructor;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.open.api.WxOpenMaEmbeddedService;
+import me.chanjar.weixin.open.bean.result.WxOpenMaEmbeddedListResult;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 半屏小程序管理服务
+ * <pre>
+ *   <a href="https://developers.weixin.qq.com/doc/oplatform/openApi/OpenApiDoc/miniprogram-management/embedded-management/addEmbedded.html">半屏小程序管理</a>
+ * </pre>
+ *
+ * @author Yuan
+ * @version 1.0.0
+ * @date 2024-12-04 16:55:19
+ */
+@AllArgsConstructor
+public class WxOpenMaEmbeddedServiceImpl implements WxOpenMaEmbeddedService {
+
+  private final WxMaService wxMaService;
+
+  /**
+   * 添加半屏小程序
+   *
+   * @param embeddedAppId 半屏小程序appId
+   * @param applyReason   申请理由
+   * @author Yuan
+   * @date 2024-12-04 17:33:33
+   */
+  @Override
+  public void addEmbedded(String embeddedAppId, String applyReason) throws WxErrorException {
+    JsonObject params = new JsonObject();
+    params.addProperty("appid", embeddedAppId);
+    if (StringUtils.isNotBlank(applyReason)) {
+      params.addProperty("apply_reason", applyReason);
+    }
+    String response = wxMaService.post(API_ADD_EMBEDDED, params);
+    WxError wxError = WxError.fromJson(response, WxType.MiniApp);
+    if (wxError.getErrorCode() != 0) {
+      throw new WxErrorException(wxError);
+    }
+  }
+
+  /**
+   * 删除半屏小程序
+   *
+   * @param embeddedAppId 半屏小程序appId
+   * @author Yuan
+   * @date 2024-12-04 17:33:33
+   */
+  @Override
+  public void deleteEmbedded(String embeddedAppId) throws WxErrorException {
+    JsonObject params = new JsonObject();
+    params.addProperty("appid", embeddedAppId);
+    String response = wxMaService.post(API_DELETE_EMBEDDED, params);
+    WxError wxError = WxError.fromJson(response, WxType.MiniApp);
+    if (wxError.getErrorCode() != 0) {
+      throw new WxErrorException(wxError);
+    }
+  }
+
+  /**
+   * 获取半屏小程序调用列表
+   *
+   * @author Yuan
+   * @date 2024-12-04 17:33:33
+   */
+  @Override
+  public WxOpenMaEmbeddedListResult getEmbeddedList() throws WxErrorException {
+    String response = wxMaService.get(API_GET_EMBEDDED_LIST, null);
+    WxError wxError = WxError.fromJson(response, WxType.MiniApp);
+    if (wxError.getErrorCode() != 0) {
+      throw new WxErrorException(wxError);
+    }
+    return WxMaGsonBuilder.create().fromJson(response, WxOpenMaEmbeddedListResult.class);
+  }
+
+  /**
+   * 取消授权小程序
+   *
+   * @param embeddedAppId 半屏小程序appId
+   * @author Yuan
+   * @date 2024-12-04 17:33:33
+   */
+  @Override
+  public void deleteAuthorizedEmbedded(String embeddedAppId) throws WxErrorException {
+    JsonObject params = new JsonObject();
+    params.addProperty("appid", embeddedAppId);
+    String response = wxMaService.post(API_DELETE_AUTHORIZED_EMBEDDED, params);
+    WxError wxError = WxError.fromJson(response, WxType.MiniApp);
+    if (wxError.getErrorCode() != 0) {
+      throw new WxErrorException(wxError);
+    }
+  }
+
+  /**
+   * 获取半屏小程序授权列表
+   *
+   * @return {@link WxOpenMaEmbeddedListResult }
+   * @author Yuan
+   * @date 2024-12-04 17:33:33
+   */
+  @Override
+  public WxOpenMaEmbeddedListResult getOwnList() throws WxErrorException {
+    String response = wxMaService.get(API_GET_OWN_LIST + "?num=1000", null);
+    WxError wxError = WxError.fromJson(response, WxType.MiniApp);
+    if (wxError.getErrorCode() != 0) {
+      throw new WxErrorException(wxError);
+    }
+    return WxMaGsonBuilder.create().fromJson(response, WxOpenMaEmbeddedListResult.class);
+  }
+
+  /**
+   * 获取半屏小程序授权列表
+   *
+   * @param start 分页起始值 ，默认值为0
+   * @param num   一次拉取最大值，最大 1000，默认值为10
+   * @return {@link WxOpenMaEmbeddedListResult }
+   * @author Yuan
+   * @date 2024-12-04 17:33:33
+   */
+  @Override
+  public WxOpenMaEmbeddedListResult getOwnList(Integer start, Integer num) throws WxErrorException {
+    if (null == start) {
+      start = 0;
+    }
+    if (null == num) {
+      num = 10;
+    }
+    if (num > 1000) {
+      num = 1000;
+    }
+    String response = wxMaService.get(API_GET_OWN_LIST + "?start=" + start + "&num=" + num, null);
+    WxError wxError = WxError.fromJson(response, WxType.MiniApp);
+    if (wxError.getErrorCode() != 0) {
+      throw new WxErrorException(wxError);
+    }
+    return WxMaGsonBuilder.create().fromJson(response, WxOpenMaEmbeddedListResult.class);
+  }
+
+  /**
+   * 设置授权方式
+   *
+   * @param flag 半屏小程序授权方式。0表示需要管理员验证；1表示自动通过；2表示自动拒绝。
+   * @author Yuan
+   * @date 2024-12-04 17:33:33
+   */
+  @Override
+  public void setAuthorizedEmbedded(Integer flag) throws WxErrorException {
+    JsonObject params = new JsonObject();
+    params.addProperty("flag", flag);
+    String response = wxMaService.post(API_SET_AUTHORIZED_EMBEDDED, params);
+    WxError wxError = WxError.fromJson(response, WxType.MiniApp);
+    if (wxError.getErrorCode() != 0) {
+      throw new WxErrorException(wxError);
+    }
+  }
+}
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaIcpServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaIcpServiceImpl.java
index dc78f22fe3..8a202ed27b 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaIcpServiceImpl.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaIcpServiceImpl.java
@@ -49,12 +49,15 @@ public WxOpenIcpVerifyTaskResult queryIcpVerifyTask(String taskId) throws WxErro
   /**
    * 发起小程序管理员人脸核身
    *
+   * @param alongWithAuth 小程序认证及备案二合一场景，填 true，否则为小程序备案场景。默认值为 false。
    * @return 人脸核验任务结果
    * @throws WxErrorException e
    */
   @Override
-  public WxOpenIcpCreateIcpVerifyTaskResult createIcpVerifyTask() throws WxErrorException {
-    String response = wxMaService.post(CREATE_ICP_VERIFY_TASK, "");
+  public WxOpenIcpCreateIcpVerifyTaskResult createIcpVerifyTask(boolean alongWithAuth) throws WxErrorException {
+    JsonObject params = new JsonObject();
+    params.addProperty("along_with_auth", alongWithAuth);
+    String response = wxMaService.post(CREATE_ICP_VERIFY_TASK, params);
     return WxMaGsonBuilder.create().fromJson(response, WxOpenIcpCreateIcpVerifyTaskResult.class);
   }
 
@@ -212,4 +215,5 @@ public File getIcpMedia(String mediaId) throws WxErrorException {
       throw new WxErrorException(WxError.builder().errorMsg(e.getMessage()).build(), e);
     }
   }
+
 }
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java
index 75be6bd4e1..85ce41fd0c 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMaServiceImpl.java
@@ -54,16 +54,22 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ
   private final WxOpenMaPrivacyService privacyService;
   @Getter
   private final WxOpenMaShoppingOrdersService shoppingOrdersService;
+  @Getter
+  private final WxOpenMaEmbeddedService embeddedService;
+  @Getter
+  private final WxOpenMaAuthAndIcpService authAndIcpService;
 
   public WxOpenMaServiceImpl(WxOpenComponentService wxOpenComponentService, String appId, WxMaConfig wxMaConfig) {
     this.wxOpenComponentService = wxOpenComponentService;
     this.appId = appId;
     this.wxMaConfig = wxMaConfig;
-    this.basicService = new WxOpenMaBasicServiceImpl(this);
+    this.basicService = new WxOpenMaBasicServiceImpl(this, wxOpenComponentService);
     this.authService = new WxOpenMaAuthServiceImpl(this);
     this.icpService = new WxOpenMaIcpServiceImpl(this);
     this.privacyService = new WxOpenMaPrivacyServiceImpl(this);
     this.shoppingOrdersService = new WxOpenMaShoppingOrdersServiceImpl(this);
+    this.embeddedService = new WxOpenMaEmbeddedServiceImpl(this);
+    this.authAndIcpService = new WxOpenMaAuthAndIcpServiceImpl(this);
     initHttp();
   }
 
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMinishopServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMinishopServiceImpl.java
index c6934d58d4..98e5d5fa82 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMinishopServiceImpl.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMinishopServiceImpl.java
@@ -2,13 +2,11 @@
 
 import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
 import cn.binarywang.wx.miniapp.config.WxMaConfig;
-import com.google.gson.Gson;
 import com.google.gson.JsonObject;
 import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.open.api.WxOpenComponentService;
 import me.chanjar.weixin.open.api.WxOpenMinishopService;
-import me.chanjar.weixin.open.api.WxOpenService;
 import me.chanjar.weixin.open.bean.minishop.*;
 import me.chanjar.weixin.open.bean.result.WxOpenResult;
 
@@ -24,7 +22,7 @@ public WxOpenMinishopServiceImpl(WxOpenComponentService wxOpenComponentService,
     this.wxOpenComponentService = wxOpenComponentService;
     this.appId = appId;
     this.wxMaConfig = wxMaConfig;
-    log.info("appId: " + appId);
+    log.info("appId: {}", appId);
     if (wxMaConfig == null) {
       log.error("WxMaConfig is null");
     }
@@ -58,7 +56,7 @@ public MinishopAuditStatus checkAuditStatus(String wxName) throws WxErrorExcepti
   @Override
   public String uploadImagePicFile(Integer height, Integer width, File file) throws WxErrorException {
     String url = UPLOAD_IMG_MINISHOP_FILE_URL + "?access_token="+getAccessToken(true)+"&height="+height+"&width="+width;
-    log.info("upload url: " + url);
+    log.info("upload url: {}", url);
     String response = post(url, file);
     return response;
   }
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java
index 576db4a22c..98411279f1 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenMpServiceImpl.java
@@ -5,9 +5,7 @@
 import com.google.gson.JsonObject;
 import lombok.SneakyThrows;
 import me.chanjar.weixin.common.error.WxErrorException;
-import me.chanjar.weixin.mp.api.WxMpService;
 import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
-import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
 import me.chanjar.weixin.mp.config.WxMpConfigStorage;
 import me.chanjar.weixin.open.api.WxOpenComponentService;
 import me.chanjar.weixin.open.api.WxOpenMpService;
@@ -16,9 +14,7 @@
 import me.chanjar.weixin.open.bean.result.WxOpenResult;
 
 import java.net.URLEncoder;
-import java.util.Map;
 import java.util.Objects;
-import java.util.function.Function;
 
 /**
  * @author <a href="https://github.com/007gzs">007</a>
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceAbstractImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceAbstractImpl.java
index 845441c2d6..bad2241aa5 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceAbstractImpl.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceAbstractImpl.java
@@ -10,8 +10,6 @@
 import me.chanjar.weixin.open.api.WxOpenComponentService;
 import me.chanjar.weixin.open.api.WxOpenConfigStorage;
 import me.chanjar.weixin.open.api.WxOpenService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceApacheHttpClientImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceApacheHttpClientImpl.java
index 2cf3b8adbf..a90dbed5c5 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceApacheHttpClientImpl.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/api/impl/WxOpenServiceApacheHttpClientImpl.java
@@ -1,6 +1,5 @@
 package me.chanjar.weixin.open.api.impl;
 
-import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
 import me.chanjar.weixin.common.bean.result.WxMinishopImageUploadResult;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.*;
@@ -53,8 +52,8 @@ public HttpHost getRequestHttpProxy() {
   }
 
   @Override
-  public HttpType getRequestType() {
-    return HttpType.APACHE_HTTP;
+  public HttpClientType getRequestType() {
+    return HttpClientType.APACHE_HTTP;
   }
 
   @Override
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/auth/MaAuthQueryIdentityTreeResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/auth/MaAuthQueryIdentityTreeResult.java
index c3960a2b55..b7660d6da4 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/auth/MaAuthQueryIdentityTreeResult.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/auth/MaAuthQueryIdentityTreeResult.java
@@ -24,6 +24,6 @@ public class MaAuthQueryIdentityTreeResult extends WxOpenResult {
    * 子节点信息 非叶子节点必有
    */
   @Nullable
-  @SerializedName("node_list")
+  @SerializedName("identity_tree_list")
   private List<MaAuthQueryIdentityTreeResultIdentityNode> nodeList;
 }
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/authandicp/WxOpenQueryAuthAndIcpResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/authandicp/WxOpenQueryAuthAndIcpResult.java
new file mode 100644
index 0000000000..2c2e9e16b6
--- /dev/null
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/authandicp/WxOpenQueryAuthAndIcpResult.java
@@ -0,0 +1,134 @@
+package me.chanjar.weixin.open.bean.authandicp;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.*;
+import me.chanjar.weixin.open.bean.result.WxOpenResult;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @author 痴货
+ * @Description
+ * @createTime 2025/06/18 23:00
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+public class WxOpenQueryAuthAndIcpResult extends WxOpenResult {
+
+  private static final long serialVersionUID = -1175687030580654852L;
+
+  /**
+   * 当前任务流程状态，见下方任务流程状态枚举
+   * 9	手机验证成功
+   * 15	等待支付认证审核费用
+   * 16	认证审核费用支付成功
+   * 17	认证审核中
+   * 18	认证审核驳回
+   * 19	认证审核通过
+   * 20	认证审核最终失败（不能再修改）
+   * 21	创建备案审核单失败
+   * 22	备案平台审核中
+   * 23	备案平台审核驳回
+   * 24	备案管局审核中
+   * 25	管局审核驳回
+   * 26	认证及备案完成
+   * 27	流程已过期
+   * 28	流程已终止
+   * 29	备案已撤回
+   */
+  @SerializedName("procedure_status")
+  private Integer procedureStatus;
+
+  /**
+   * 小程序后台展示的认证订单号
+   */
+  @SerializedName("orderid")
+  private Integer orderId;
+
+  /**
+   * 小程序认证审核单被驳回（procedure_status 为 18）时有效
+   */
+  @SerializedName("refill_reason")
+  private String refillReason;
+
+  /**
+   * 小程序认证审核最终失败的原因（procedure_status 为 20）时有效
+   */
+  @SerializedName("fail_reason")
+  private String failReason;
+
+  /**
+   * 小程序备案相关信息
+   */
+  @SerializedName("icp_audit")
+  private IcpAudit icpAudit;
+
+  @Getter
+  @Setter
+  @NoArgsConstructor
+  public static class IcpAudit implements Serializable {
+
+    private static final long serialVersionUID = 879913578852421216L;
+
+    /**
+     * 错误提示，创建备案审核单失败时返回（procedure_status 为 21）
+     */
+    @SerializedName("hints")
+    private List<Hint> hints;
+
+    /**
+     * 驳回原因，备案不通过时返回（procedure_status 为 23、25）
+     */
+    @SerializedName("audit_data")
+    private AuditData auditData;
+
+    /**
+     * 管局短信核验状态，仅当任务流程状态为 24（备案管局审核中）的时候才有效。1：等待核验中，2：核验完成，3：核验超时。
+     */
+    @SerializedName("sms_verify_status")
+    private Integer smsVerifyStatus;
+
+  }
+
+  @Getter
+  @Setter
+  @NoArgsConstructor
+  public static class AuditData implements Serializable {
+
+    private static final long serialVersionUID = 2217833539540191890L;
+
+    /**
+     * 审核不通过的字段中文名
+     */
+    @SerializedName("key_name")
+    private String keyName;
+
+    /**
+     * 字段不通过的原因
+     */
+    @SerializedName("error")
+    private String error;
+
+    /**
+     * 修改建议
+     */
+    @SerializedName("suggest")
+    private String suggest;
+  }
+
+  @Data
+  @EqualsAndHashCode(callSuper = true)
+  public static class Hint extends WxOpenResult {
+
+    private static final long serialVersionUID = 6585787444231265854L;
+
+    /**
+     * 校验失败的字段
+     */
+    @SerializedName("err_field")
+    private String errField;
+  }
+
+}
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/authandicp/WxOpenSubmitAuthAndIcpParam.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/authandicp/WxOpenSubmitAuthAndIcpParam.java
new file mode 100644
index 0000000000..3de4a0c9aa
--- /dev/null
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/authandicp/WxOpenSubmitAuthAndIcpParam.java
@@ -0,0 +1,767 @@
+package me.chanjar.weixin.open.bean.authandicp;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import me.chanjar.weixin.open.api.WxOpenMaIcpService;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @author 痴货
+ * @Description
+ * @createTime 2025/06/18 23:00
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxOpenSubmitAuthAndIcpParam implements Serializable {
+
+  private static final long serialVersionUID = 5545621231231213158L;
+
+  /**
+   * 认证数据
+   */
+  @SerializedName("auth_data")
+  private AuthData authData;
+
+  /**
+   * 备案主体信息
+   */
+  @SerializedName("icp_subject")
+  private IcpSubject icpSubject;
+
+  /**
+   * 微信小程序信息
+   */
+  @SerializedName("icp_applets")
+  private IcpApplets icpApplets;
+
+  /**
+   * 其他备案媒体材料
+   */
+  @SerializedName("icp_materials")
+  private IcpMaterials icpMaterials;
+
+
+  @Data
+  @Builder
+  @NoArgsConstructor
+  @AllArgsConstructor
+  public static class AuthData implements Serializable {
+
+    private static final long serialVersionUID = 5545289494161613158L;
+
+    /**
+     * 联系人信息
+     */
+    @SerializedName("contact_info")
+    private ContactInfo contactInfo;
+
+    /**
+     * 发票信息，如果是服务商代缴模式，不需要填写
+     */
+    @SerializedName("invoice_info")
+    private InvoiceInfo invoiceInfo;
+
+    /**
+     * 认证主体类型：1.企业；12.个体工商户；15.个人
+     */
+    @SerializedName("customer_type")
+    private Integer customerType;
+
+    /**
+     * 支付方式 1：消耗服务商预购包 2：小程序开发者自行支付
+     */
+    @SerializedName("pay_type")
+    private Integer payType;
+
+    /**
+     * 主体资质其他证明材料，最多上传10张图片
+     */
+    @SerializedName("qualification_other")
+    private List<String> qualificationOther;
+
+    /**
+     * 小程序账号名称
+     */
+    @SerializedName("account_name")
+    private String accountName;
+
+    /**
+     * 小程序账号名称命名类型 1：基于自选词汇命名 2：基于商标命名
+     */
+    @SerializedName("account_name_type")
+    private String accountNameType;
+
+    /**
+     * 名称命中关键词-补充材料，支持上传多张图片
+     */
+    @SerializedName("account_supplemental")
+    private List<String> accountSupplemental;
+
+    /**
+     * 认证类型为个人类型时可以选择要认证的身份，从 查询个人认证身份选项列表 里获取，填叶节点的name
+     */
+    @SerializedName("auth_identification")
+    private String authIdentification;
+
+    /**
+     * 填了 auth_identification 则必填。身份证明材料 （1）基于不同认证身份上传不同的材料；（2）认证类型=1时选填，支持上传10张图片
+     */
+    @SerializedName("auth_ident_material")
+    private List<String> authIdentMaterial;
+
+    /**
+     * 第三方联系电话
+     */
+    @SerializedName("third_party_phone")
+    private String thirdPartyPhone;
+
+    /**
+     * 选择服务商代缴模式时必填。服务市场 appid，该服务市场账号主体必须与服务商账号主体一致
+     */
+    @SerializedName("service_appid")
+    private String serviceAppid;
+
+  }
+
+  @Data
+  @Builder
+  @NoArgsConstructor
+  @AllArgsConstructor
+  public static class ContactInfo implements Serializable {
+
+    private static final long serialVersionUID = -2962862643438222305L;
+
+    /**
+     * 认证联系人姓名
+     */
+    @SerializedName("name")
+    private String name;
+
+    /**
+     * 认证联系人邮箱
+     */
+    @SerializedName("email")
+    private String email;
+
+    /**
+     * 认证联系人手机号
+     */
+    @SerializedName("mobile")
+    private String mobile;
+
+  }
+
+  @Data
+  @Builder
+  @NoArgsConstructor
+  @AllArgsConstructor
+  public static class InvoiceInfo implements Serializable {
+
+    private static final long serialVersionUID = 4564894651613131322L;
+
+    /**
+     * 发票类型 1: 不开发票 2: 电子发票 4: 增值税专票（数电类型）
+     */
+    @SerializedName("invoice_type")
+    private String invoiceType;
+
+    /**
+     * 发票类型=2时必填 电子发票开票信息
+     */
+    @SerializedName("electronic")
+    private Electronic electronic;
+
+    /**
+     * 发票类型=4时必填 增值税专票（数电类型）开票信息
+     */
+    @SerializedName("vat")
+    private Vat vat;
+
+  }
+
+  @Data
+  @Builder
+  @NoArgsConstructor
+  @AllArgsConstructor
+  public static class Electronic implements Serializable {
+
+    private static final long serialVersionUID = 189498465135131444L;
+
+    /**
+     * 纳税识别号（15位、17、18或20位）
+     */
+    @SerializedName("id")
+    private String id;
+
+    /**
+     * 发票备注（选填）
+     */
+    @SerializedName("desc")
+    private String desc;
+
+  }
+
+  @Data
+  @Builder
+  @NoArgsConstructor
+  @AllArgsConstructor
+  public static class Vat implements Serializable {
+
+    private static final long serialVersionUID = 829892829816551512L;
+
+    /**
+     * 企业电话
+     */
+    @SerializedName("enterprise_phone")
+    private String enterprisePhone;
+
+    /**
+     * 纳税识别号（15位、17、18或20位）
+     */
+    @SerializedName("id")
+    private String id;
+
+    /**
+     * 企业注册地址
+     */
+    @SerializedName("enterprise_address")
+    private String enterpriseAddress;
+
+    /**
+     * 企业开户银行（选填）
+     */
+    @SerializedName("bank_name")
+    private String bankName;
+
+    /**
+     * 企业银行账号（选填）
+     */
+    @SerializedName("bank_account")
+    private String bankAccount;
+
+    /**
+     * 发票备注（选填）
+     */
+    @SerializedName("desc")
+    private String desc;
+
+  }
+
+  @Data
+  @Builder
+  @NoArgsConstructor
+  @AllArgsConstructor
+  public static class IcpSubject implements Serializable {
+
+    private static final long serialVersionUID = -1256165165165165165L;
+
+    /**
+     * 主体基本信息
+     */
+    @SerializedName("base_info")
+    private SubjectBaseInfo baseInfo;
+
+    /**
+     * 个人主体额外信息
+     */
+    @SerializedName("personal_info")
+    private SubjectPersonalInfo personalInfo;
+
+    /**
+     * 主体额外信息（个人备案时，如果存在与主体负责人信息相同的字段，则填入相同的值）
+     */
+    @SerializedName("organize_info")
+    private SubjectOrganizeInfo organizeInfo;
+
+    /**
+     * 主体负责人信息
+     */
+    @SerializedName("principal_info")
+    private SubjectPrincipalInfo principalInfo;
+
+    /**
+     * 法人信息（非个人备案，且主体负责人不是法人时，必填）
+     */
+    @SerializedName("legal_person_info")
+    private SubjectLegalPersonInfo legalPersonInfo;
+  }
+
+  @Data
+  @Builder
+  @NoArgsConstructor
+  @AllArgsConstructor
+  public static class SubjectBaseInfo implements Serializable {
+
+    private static final long serialVersionUID = -1561561613212313445L;
+
+    /**
+     * 主体性质，选项参考 获取单位性质，**仅支持企业、个体工商户、个人**
+     * {@link WxOpenMaIcpService#queryIcpSubjectTypes }
+     */
+    @SerializedName("type")
+    private Integer type;
+
+    /**
+     * 主办单位名称
+     */
+    @SerializedName("name")
+    private String name;
+
+    /**
+     * 备案省份，使用省份代码
+     */
+    @SerializedName("province")
+    private String province;
+
+    /**
+     * 备案城市，使用城市代码
+     */
+    @SerializedName("city")
+    private String city;
+
+    /**
+     * 备案县区，使用县区代码
+     */
+    @SerializedName("district")
+    private String district;
+
+    /**
+     * 通讯地址，必须属于备案省市区，地址开头的省市区不用填入
+     */
+    @SerializedName("address")
+    private String address;
+
+    /**
+     * 主体信息备注，根据需要，如实填写
+     */
+    @SerializedName("comment")
+    private String comment;
+
+    /**
+     * 主体备案号
+     */
+    @SerializedName("record_number")
+    private String recordNumber;
+
+  }
+
+  @Data
+  @Builder
+  @NoArgsConstructor
+  @AllArgsConstructor
+  public static class SubjectPersonalInfo implements Serializable {
+
+    private static final long serialVersionUID = -2151981561916519288L;
+
+    /**
+     * 临时居住证明照片 media_id，个人备案且非本省人员，需要提供居住证、暂住证、社保证明、房产证等临时居住证明
+     */
+    @SerializedName("residence_permit")
+    private String residencePermit;
+
+  }
+
+  @Data
+  @Builder
+  @NoArgsConstructor
+  @AllArgsConstructor
+  public static class SubjectOrganizeInfo implements Serializable {
+
+    private static final long serialVersionUID = -1181121318132185161L;
+
+    /**
+     * 主体证件类型
+     * {@link WxOpenMaIcpService#queryIcpCertificateTypes}
+     */
+    @SerializedName("certificate_type")
+    private Integer certificateType;
+
+    /**
+     * 主体证件号码
+     */
+    @SerializedName("certificate_number")
+    private String certificateNumber;
+
+    /**
+     * 主体证件住所
+     */
+    @SerializedName("certificate_address")
+    private String certificateAddress;
+
+    /**
+     * 主体证件照片 media_id，如果小程序主体为非个人类型
+     */
+    @SerializedName("certificate_photo")
+    private String certificatePhoto;
+
+  }
+  @Data
+  @Builder
+  @NoArgsConstructor
+  @AllArgsConstructor
+  public static class SubjectPrincipalInfo implements Serializable {
+
+    private static final long serialVersionUID = -2984191321918916511L;
+
+    /**
+     * 负责人姓名
+     */
+    @SerializedName("name")
+    private String name;
+
+    /**
+     * 负责人联系方式
+     */
+    @SerializedName("mobile")
+    private String mobile;
+
+    /**
+     * 负责人电子邮件
+     */
+    @SerializedName("email")
+    private String email;
+
+    /**
+     * 负责人应急联系方式
+     */
+    @SerializedName("emergency_contact")
+    private String emergencyContact;
+
+    /**
+     * 负责人证件类型(获取证件类型
+     * {@link WxOpenMaIcpService#queryIcpCertificateTypes()})
+     */
+    @SerializedName("certificate_type")
+    private Integer certificateType;
+
+    /**
+     * 负责人证件号码
+     */
+    @SerializedName("certificate_number")
+    private String certificateNumber;
+
+    /**
+     * 负责人证件有效期起始日期，格式为 YYYYmmdd
+     */
+    @SerializedName("certificate_validity_date_start")
+    private String certificateValidityDateStart;
+
+    /**
+     * 负责人证件有效期终止日期，格式为 YYYYmmdd
+     */
+    @SerializedName("certificate_validity_date_end")
+    private String certificateValidityDateEnd;
+
+    /**
+     * 负责人证件正面照片 media_id（身份证为人像面）
+     */
+    @SerializedName("certificate_photo_front")
+    private String certificatePhotoFront;
+
+    /**
+     * 负责人证件背面照片 media_id（身份证为国徽面）
+     */
+    @SerializedName("certificate_photo_back")
+    private String certificatePhotoBack;
+
+    /**
+     * 授权书 media_id，当主体负责人不是法人时需要主体负责人授权书，当小程序负责人不是法人时需要小程序负责人授权书
+     */
+    @SerializedName("authorization_letter")
+    private String authorizationLetter;
+
+    /**
+     * 扫脸认证任务id(扫脸认证接口返回的task_id)，仅小程序负责人需要扫脸，主体负责人无需扫脸
+     */
+    @SerializedName("verify_task_id")
+    private String verifyTaskId;
+
+  }
+  @Data
+  @Builder
+  @NoArgsConstructor
+  @AllArgsConstructor
+  public static class SubjectLegalPersonInfo implements Serializable {
+
+    private static final long serialVersionUID = -1259198165316516161L;
+
+    /**
+     * 法人代表姓名
+     */
+    @SerializedName("name")
+    private String name;
+
+    /**
+     * 法人证件号码
+     */
+    @SerializedName("certificate_number")
+    private String certificateNumber;
+
+  }
+
+  @Data
+  @Builder
+  @NoArgsConstructor
+  @AllArgsConstructor
+  public static class IcpApplets implements Serializable {
+
+    private static final long serialVersionUID = -2156129841651651651L;
+
+    /**
+     * 微信小程序基本信息
+     */
+    @SerializedName("base_info")
+    private AppletsBaseInfo baseInfo;
+
+    /**
+     * 小程序负责人信息
+     */
+    @SerializedName("principal_info")
+    private AppletsPrincipalInfo principalInfo;
+
+  }
+
+  @Data
+  @Builder
+  @NoArgsConstructor
+  @AllArgsConstructor
+  public static class AppletsBaseInfo implements Serializable {
+
+    private static final long serialVersionUID = 8404017028547715919L;
+
+    /**
+     * 小程序ID，不用填写，后台自动拉取
+     */
+    @SerializedName("appid")
+    private String appId;
+
+    /**
+     * 小程序名称，不用填写，后台自动拉取
+     */
+    @SerializedName("name")
+    private String name;
+
+    /**
+     * 小程序服务内容类型，只能填写二级服务内容类型，最多5个
+     * {@link WxOpenMaIcpService#queryIcpServiceContentTypes}
+     */
+    @SerializedName("service_content_types")
+    private List<Integer> serviceContentTypes;
+
+    /**
+     * 前置审批项，列表中不能存在重复的前置审批类型id，如不涉及前置审批项，也需要填“以上都不涉及”
+     */
+    @SerializedName("nrlx_details")
+    private List<AppletsNrlxDetailItem> nrlxDetails;
+
+    /**
+     * 请具体描述小程序实际经营内容、主要服务内容，该信息为主管部门审核重要依据，备注内容字数限制20-200字，请认真填写。
+     */
+    @SerializedName("comment")
+    private String comment;
+
+    /**
+     * 小程序备案号，示例值：粤B2-20090059-1626X
+     * （申请小程序备案时不用填写，查询已备案详情时会返回）
+     */
+    @SerializedName("record_number")
+    private String recordNumber;
+  }
+
+  @Data
+  @Builder
+  @NoArgsConstructor
+  @AllArgsConstructor
+  public static class AppletsNrlxDetailItem implements Serializable {
+
+    private static final long serialVersionUID = -9144721738792167000L;
+
+    /**
+     * 前置审批类型
+     * {@link WxOpenMaIcpService#queryIcpNrlxTypes}
+     */
+    @SerializedName("type")
+    private Integer type;
+
+    /**
+     * 前置审批号，如果前置审批类型不是“以上都不涉及”，
+     * 则必填，示例值："粤-12345号
+     */
+    @SerializedName("code")
+    private String code;
+
+    /**
+     * 前置审批媒体材料 media_id
+     */
+    @SerializedName("media")
+    private String media;
+  }
+
+  @Data
+  @Builder
+  @NoArgsConstructor
+  @AllArgsConstructor
+  public static class AppletsPrincipalInfo implements Serializable {
+
+    private static final long serialVersionUID = 5088256283066784463L;
+
+    /**
+     * 负责人姓名
+     */
+    @SerializedName("name")
+    private String name;
+
+    /**
+     * 负责人联系方式
+     */
+    @SerializedName("mobile")
+    private String mobile;
+
+    /**
+     * 负责人电子邮件
+     */
+    @SerializedName("email")
+    private String email;
+
+    /**
+     * 负责人应急联系方式
+     */
+    @SerializedName("emergency_contact")
+    private String emergencyContact;
+
+    /**
+     * 负责人证件类型
+     * {@link WxOpenMaIcpService#queryIcpCertificateTypes}
+     */
+    @SerializedName("certificate_type")
+    private Integer certificateType;
+
+    /**
+     * 负责人证件号码
+     */
+    @SerializedName("certificate_number")
+    private String certificateNumber;
+
+    /**
+     * 负责人证件有效期起始日期，
+     * 格式为 YYYYmmdd，示例值："20230815"
+     */
+    @SerializedName("certificate_validity_date_start")
+    private String certificateValidityDateStart;
+
+    /**
+     * 负责人证件有效期终止日期，
+     * 格式为 YYYYmmdd，
+     * 如证件长期有效，请填写 "长期"，示例值："20330815"
+     */
+    @SerializedName("certificate_validity_date_end")
+    private String certificateValidityDateEnd;
+
+    /**
+     * 负责人证件正面照片 media_id
+     * （身份证为人像面）
+     */
+    @SerializedName("certificate_photo_front")
+    private String certificatePhotoFront;
+
+    /**
+     * 负责人证件背面照片 media_id
+     * （身份证为国徽面）
+     */
+    @SerializedName("certificate_photo_back")
+    private String certificatePhotoBack;
+
+    /**
+     * 授权书 media_id，
+     * 当主体负责人不是法人时需要主体负责人授权书，
+     * 当小程序负责人不是法人时需要小程序负责人授权书
+     */
+    @SerializedName("authorization_letter")
+    private String authorizationLetter;
+
+    /**
+     * 扫脸认证任务id(扫脸认证接口返回的task_id)，
+     * 仅小程序负责人需要扫脸，主体负责人无需扫脸
+     */
+    @SerializedName("verify_task_id")
+    private String verifyTaskId;
+  }
+
+  @Data
+  @Builder
+  @NoArgsConstructor
+  @AllArgsConstructor
+  public static class IcpMaterials implements Serializable {
+
+    private static final long serialVersionUID = -2651654844198165191L;
+
+    /**
+     * 互联网信息服务承诺书 media_id，最多上传1个
+     */
+    @SerializedName("commitment_letter")
+    private List<String> commitmentLetter;
+
+    /**
+     * 主体更名函 media_id(非个人类型，且发生过更名时需要上传)，最多上传1个
+     */
+    @SerializedName("business_name_change_letter")
+    private List<String> businessNameChangeLetter;
+
+    /**
+     * 党建确认函 media_id，最多上传1个
+     */
+    @SerializedName("party_building_confirmation_letter")
+    private List<String> partyBuildingConfirmationLetter;
+
+    /**
+     * 承诺视频 media_id，最多上传1个
+     */
+    @SerializedName("promise_video")
+    private List<String> promiseVideo;
+
+    /**
+     * 网站备案信息真实性责任告知书 media_id，最多上传1个
+     */
+    @SerializedName("authenticity_responsibility_letter")
+    private List<String> authenticityResponsibilityLetter;
+
+    /**
+     * 小程序备案信息真实性承诺书 media_id，最多上传1个
+     */
+    @SerializedName("authenticity_commitment_letter")
+    private List<String> authenticityCommitmentLetter;
+
+    /**
+     * 小程序建设方案书 media_id，最多上传1个
+     */
+    @SerializedName("website_construction_proposal")
+    private List<String> websiteConstructionProposal;
+
+    /**
+     * 主体其它附件 media_id，最多上传10个
+     */
+    @SerializedName("subject_other_materials")
+    private List<String> subjectOtherMaterials;
+
+    /**
+     * 小程序其它附件 media_id，最多上传10个
+     */
+    @SerializedName("applets_other_materials")
+    private List<String> appletsOtherMaterials;
+
+    /**
+     * 手持证件照 media_id，最多上传1个
+     */
+    @SerializedName("holding_certificate_photo")
+    private List<String> holdingCertificatePhoto;
+
+  }
+
+}
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/authandicp/WxOpenSubmitAuthAndIcpResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/authandicp/WxOpenSubmitAuthAndIcpResult.java
new file mode 100644
index 0000000000..08dbc80f2b
--- /dev/null
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/authandicp/WxOpenSubmitAuthAndIcpResult.java
@@ -0,0 +1,52 @@
+package me.chanjar.weixin.open.bean.authandicp;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.*;
+import me.chanjar.weixin.open.bean.result.WxOpenResult;
+
+import java.util.List;
+
+/**
+ * @author 痴货
+ * @Description
+ * @createTime 2025/06/18 23:00
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+public class WxOpenSubmitAuthAndIcpResult extends WxOpenResult {
+
+  private static final long serialVersionUID = -1175687058498454852L;
+
+  /**
+   * 错误提示
+   */
+  @SerializedName("hints")
+  private List<Hint> hints;
+
+  /**
+   * 小程序认证及备案任务流程 id
+   */
+  @SerializedName("procedure_id")
+  private String procedureId;
+
+  /**
+   * 小程序认证认证审核费用付费链接，当 pay_type 为 2 时返回
+   */
+  @SerializedName("pay_url")
+  private String payUrl;
+
+  @Data
+  @EqualsAndHashCode(callSuper = true)
+  public static class Hint extends WxOpenResult {
+
+    private static final long serialVersionUID = 6585787444231265854L;
+
+    /**
+     * 校验失败的字段
+     */
+    @SerializedName("err_field")
+    private String errField;
+  }
+
+}
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenApplyIcpFilingParam.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenApplyIcpFilingParam.java
index 37f84cf3d5..c09bfc73f6 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenApplyIcpFilingParam.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenApplyIcpFilingParam.java
@@ -2,6 +2,7 @@
 
 import com.google.gson.annotations.SerializedName;
 import lombok.*;
+import lombok.experimental.SuperBuilder;
 
 import java.io.Serializable;
 import java.util.List;
@@ -12,7 +13,7 @@
  * @createTime 2024/08/14 15:09
  */
 @Data
-@Builder
+@SuperBuilder
 @NoArgsConstructor
 @AllArgsConstructor
 public class WxOpenApplyIcpFilingParam implements Serializable {
@@ -312,7 +313,7 @@ public static class Applets implements Serializable {
      * 微信小程序基本信息
      */
     @SerializedName("base_info")
-    private AppletsBaseInfo basInfo;
+    private AppletsBaseInfo baseInfo;
 
     /**
      * 小程序负责人信息
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenCreateIcpVerifyTaskParam.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenCreateIcpVerifyTaskParam.java
new file mode 100644
index 0000000000..25be43a337
--- /dev/null
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenCreateIcpVerifyTaskParam.java
@@ -0,0 +1,26 @@
+package me.chanjar.weixin.open.bean.icp;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author 痴货
+ * @Description 发起小程序管理员人脸核身
+ * @createTime 2025/06/21 00:20
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxOpenCreateIcpVerifyTaskParam {
+
+  /**
+   * 小程序认证及备案二合一场景，填 true，否则为小程序备案场景。默认值为 false
+   */
+  @SerializedName("along_with_auth")
+  private Boolean alongWithAuth;
+
+}
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenIcpCreateIcpVerifyTaskResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenIcpCreateIcpVerifyTaskResult.java
index 8deb401335..f2ff3d166d 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenIcpCreateIcpVerifyTaskResult.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenIcpCreateIcpVerifyTaskResult.java
@@ -1,7 +1,5 @@
 package me.chanjar.weixin.open.bean.icp;
 
-import com.fasterxml.jackson.annotation.JsonProperty;
-
 import com.google.gson.annotations.SerializedName;
 import lombok.Getter;
 import lombok.NoArgsConstructor;
@@ -26,4 +24,10 @@ public class WxOpenIcpCreateIcpVerifyTaskResult extends WxOpenResult {
   @SerializedName("task_id")
   private String taskId;
 
+  /**
+   * 人脸核验任务url，{@link WxOpenCreateIcpVerifyTaskParam#alongWithAuth } 填 true 时返回
+   */
+  @SerializedName("verify_url")
+  private String verifyUrl;
+
 }
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenIcpVerifyTaskResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenIcpVerifyTaskResult.java
index cb59fac1c0..5290748b2a 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenIcpVerifyTaskResult.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenIcpVerifyTaskResult.java
@@ -30,4 +30,10 @@ public class WxOpenIcpVerifyTaskResult extends WxOpenResult {
    */
   @SerializedName("face_status")
   private Integer faceStatus;
+
+  /**
+   * 发起时 along_with_auth 填 true 时有效：9. 认证短信核验通过。
+   */
+  @SerializedName("along_with_auth_result")
+  private Integer alongWithAuthResult;
 }
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenOnlineIcpOrderResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenOnlineIcpOrderResult.java
index 89f8e8c397..a2a662441b 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenOnlineIcpOrderResult.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenOnlineIcpOrderResult.java
@@ -1,7 +1,6 @@
 package me.chanjar.weixin.open.bean.icp;
 
 import java.io.Serializable;
-import java.util.List;
 
 import com.google.gson.annotations.SerializedName;
 
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenQueryAuthAndIcpResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenQueryAuthAndIcpResult.java
new file mode 100644
index 0000000000..42a996d9b4
--- /dev/null
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenQueryAuthAndIcpResult.java
@@ -0,0 +1,85 @@
+package me.chanjar.weixin.open.bean.icp;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.*;
+import me.chanjar.weixin.open.bean.result.WxOpenResult;
+
+import java.util.List;
+
+/**
+ * @author xzh
+ * @Description
+ * @createTime 2024/12/19 16:56
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+public class WxOpenQueryAuthAndIcpResult extends WxOpenResult {
+  private static final long serialVersionUID = 1626895037788760364L;
+
+
+  /**
+   * 当前任务流程状态，见下方任务流程状态枚举
+   * 值	含义
+   * 15	等待支付认证审核费用
+   * 16	认证审核费用支付成功
+   * 17	认证审核中
+   * 18	认证审核驳回
+   * 19	认证审核通过
+   * 20	认证审核最终失败（不能再修改）
+   * 21	创建备案审核单失败
+   * 22	备案平台审核中
+   * 23	备案平台审核驳回
+   * 24	备案管局审核中
+   * 25	管局审核驳回
+   * 26	认证及备案完成
+   */
+  @SerializedName("procedure_status")
+  private Integer procedureStatus;
+
+  /**
+   * 小程序后台展示的认证订单号
+   */
+  @SerializedName("orderid")
+  private Long orderId;
+
+  /**
+   * 小程序认证审核单被驳回（procedure_status 为 18）时有效
+   */
+  @SerializedName("refill_reason")
+  private String refillReason;
+  /**
+   * 小程序认证审核最终失败的原因（procedure_status 为 20）时有效
+   */
+  @SerializedName("fail_reason")
+  private String failReason;
+
+  /**
+   * 小程序备案相关信息
+   */
+  @SerializedName("icp_audit")
+  private IcpAudit icpAudit;
+
+  @Data
+  public static class IcpAudit {
+
+    /**
+     * 错误提示，创建备案审核单失败时返回（procedure_status 为 21）
+     */
+    @SerializedName("hints")
+    private List<WxOpenApplyIcpFilingResult.Hint> hints;
+
+    /**
+     * 驳回原因，备案不通过时返回（procedure_status 为 23、25）
+     */
+    @SerializedName("audit_data")
+    private List<WxOpenIcpEntranceInfoResult.AuditData> auditData;
+
+    /**
+     * 管局短信核验状态，仅当任务流程状态为 24（备案管局审核中）的时候才有效。1：等待核验中，2：核验完成，3：核验超时。
+     */
+    @SerializedName("sms_verify_status")
+    private Integer smsVerifyStatus;
+  }
+
+}
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenSubmitAuthAndIcpParam.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenSubmitAuthAndIcpParam.java
new file mode 100644
index 0000000000..31d4f158f8
--- /dev/null
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenSubmitAuthAndIcpParam.java
@@ -0,0 +1,29 @@
+package me.chanjar.weixin.open.bean.icp;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.SuperBuilder;
+import me.chanjar.weixin.open.bean.auth.MaAuthSubmitParamAuthData;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author xzh
+ * @Description
+ * @createTime 2024/12/19 16:42
+ */
+@Data
+@SuperBuilder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxOpenSubmitAuthAndIcpParam extends WxOpenApplyIcpFilingParam {
+  private static final long serialVersionUID = -1302523168779484802L;
+
+  /**
+   * 认证信息
+   */
+  @NotNull
+  @SerializedName("auth_data")
+  private MaAuthSubmitParamAuthData authData;
+}
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenSubmitAuthAndIcpResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenSubmitAuthAndIcpResult.java
new file mode 100644
index 0000000000..53f04412f5
--- /dev/null
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenSubmitAuthAndIcpResult.java
@@ -0,0 +1,30 @@
+package me.chanjar.weixin.open.bean.icp;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * @author xzh
+ * @Description
+ * @createTime 2024/12/19 16:47
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+public class WxOpenSubmitAuthAndIcpResult extends WxOpenApplyIcpFilingResult {
+  private static final long serialVersionUID = 2338143380820535842L;
+
+  /**
+   * 小程序认证及备案任务流程 id
+   */
+  @SerializedName("procedure_id")
+  private String procedureId;
+
+  /**
+   * 小程序认证认证审核费用付费链接，当 pay_type 为 2 时返回
+   */
+  @SerializedName("pay_url")
+  private String payUrl;
+}
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenUploadIcpMediaResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenUploadIcpMediaResult.java
index 04977113e1..b116bef069 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenUploadIcpMediaResult.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/icp/WxOpenUploadIcpMediaResult.java
@@ -5,7 +5,6 @@
 import lombok.Getter;
 import lombok.NoArgsConstructor;
 import lombok.Setter;
-import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
 import me.chanjar.weixin.open.bean.result.WxOpenResult;
 
 /**
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenCommitExtInfo.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenCommitExtInfo.java
index 93d2a095b8..07c89a06f2 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenCommitExtInfo.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxMaOpenCommitExtInfo.java
@@ -94,6 +94,26 @@ public class WxMaOpenCommitExtInfo implements Serializable {
   @SerializedName("tabBar")
   private WxMaOpenTabBar tabBar;
 
+  /**
+   * 关于新增 requiredPrivateInfos 说明
+   * 关于地理位置接口新增与相关流程调整可以查看社区公告：
+   * <a href="https://developers.weixin.qq.com/community/develop/doc/000a02f2c5026891650e7f40351c01">点击查看</a>
+   * 7.14后，在代码中使用的地理位置相关接口（共计 8 个，见表1），第三方开发者均需要在 ext_json 参数中 requiredPrivateInfos 配置项中声明
+   * 在ext_json参数中配置requiredPrivateInfos，其规则为「整体替换」。即如果在 app.json 里也配置了，那么最终会是ext_json的配置会覆盖 app.json
+   * 配置的requiredPrivateInfos。其余规则可查看下方的「ext_json补充说明」
+   * 在ext_json参数中配置 requiredPrivateInfos 示例如下
+   * {
+   * "template_id": "95",
+   * "ext_json": "{\"requiredPrivateInfos\":[\"onLocationChange\",\"startLocationUpdate\"]}",
+   * "user_version": "V1.0",
+   * "user_desc": "test"
+   * }
+   * requiredPrivateInfos主要会检查格式是否正确，填入的 api 名称是否正确，填入的 api 名称是否有权限，填入的 api 名称是否互斥。对应的错误码可查看文档末尾的错误码文档。
+   * requiredPrivateInfos在2022.7.14后才会生效，文档提前更新是为了方便开发者可以提前了解接口的参数变更规则，提前进行调整。
+   */
+  @SerializedName("requiredPrivateInfos")
+  private String[] requiredPrivateInfos;
+
   /**
    * 添加扩展项
    *
@@ -101,10 +121,12 @@ public class WxMaOpenCommitExtInfo implements Serializable {
    * @param value
    */
   public void addExt(String key, String value) {
-    if (extMap == null)
+    if (extMap == null) {
       extMap = new HashMap<>();
-    if (StringUtils.isNoneBlank(key, value))
+    }
+    if (StringUtils.isNoneBlank(key, value)) {
       extMap.put(key, value);
+    }
   }
 
   /**
@@ -114,10 +136,12 @@ public void addExt(String key, String value) {
    * @param page
    */
   public void addExtPage(String pagePath, WxMaOpenPage page) {
-    if (extPages == null)
+    if (extPages == null) {
       extPages = new HashMap<>();
-    if (StringUtils.isNotBlank(pagePath) && page != null)
+    }
+    if (StringUtils.isNotBlank(pagePath) && page != null) {
       extPages.put(pagePath, page);
+    }
   }
 
   /**
@@ -126,10 +150,12 @@ public void addExtPage(String pagePath, WxMaOpenPage page) {
    * @param pagePath
    */
   public void addPage(String pagePath) {
-    if (pageList == null)
+    if (pageList == null) {
       pageList = new ArrayList<>();
-    if (StringUtils.isNotBlank(pagePath))
+    }
+    if (StringUtils.isNotBlank(pagePath)) {
       pageList.add(pagePath);
+    }
   }
 
   public static WxMaOpenCommitExtInfo INSTANCE() {
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaEmbedded.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaEmbedded.java
new file mode 100644
index 0000000000..e408b3baf4
--- /dev/null
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/ma/WxOpenMaEmbedded.java
@@ -0,0 +1,59 @@
+package me.chanjar.weixin.open.bean.ma;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder;
+
+import java.io.Serializable;
+
+/**
+ * 微信开放平台半屏小程序信息
+ *
+ * @author Yuan
+ * @version 1.0.0
+ * @date 2024-12-04 17:57:40
+ */
+@Data
+public class WxOpenMaEmbedded implements Serializable {
+  private static final long serialVersionUID = -7319330493157204072L;
+
+  /**
+   * 半屏小程序appid
+   */
+  @SerializedName("appid")
+  private String appId;
+  /**
+   * 添加时间
+   */
+  @SerializedName("create_time")
+  private Long createTime;
+  /**
+   * 头像url
+   */
+  @SerializedName("headimg")
+  private String headImg;
+  /**
+   * 半屏小程序昵称
+   */
+  @SerializedName("nickname")
+  private String nickName;
+  /**
+   * 申请理由
+   */
+  @SerializedName("reason")
+  private String reason;
+  /**
+   * 申请状态,1-待验证，2-已通过，3-已拒绝，4-已超时，5-已撤销，6-已取消授权
+   */
+  @SerializedName("status")
+  private String status;
+
+  @Override
+  public String toString() {
+    return WxOpenGsonBuilder.create().toJson(this);
+  }
+
+  public String toJson() {
+    return WxOpenGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/message/WxOpenXmlMessage.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/message/WxOpenXmlMessage.java
index dc6839c1a5..9185a4e030 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/message/WxOpenXmlMessage.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/message/WxOpenXmlMessage.java
@@ -140,6 +140,11 @@ public class WxOpenXmlMessage implements Serializable {
    */
   @XStreamAlias("result")
   private Integer result;
+  /**
+   * 发起时 along_with_auth 填 true 时有效：9. 认证短信核验通过。
+   */
+  @XStreamAlias("along_with_auth_result")
+  private Integer alongWithAuthResult;
   //endregion
 
   //region 当备案审核被驳回或通过时会推送该事件 推送的消息 infoType=notify_apply_icpfiling_result
@@ -155,6 +160,45 @@ public class WxOpenXmlMessage implements Serializable {
   private Integer beianStatus;
   //endregion
 
+  //region 认证及备案流程的主要节点均有事件推送到第三方平台的授权事件接收接口，包括支付完成、派单给审核机构、审核打回、审核通过、审核失败等。消息类型，固定为 notify_3rd_wxa_auth_and_icp
+
+  /**
+   * 小程序认证及备案任务流程id
+   */
+  @XStreamAlias("procedure_id")
+  private String procedureId;
+
+  /**
+   * 任务流程状态
+   * 9	手机验证成功
+   * 15	等待支付认证审核费用
+   * 16	认证审核费用支付成功
+   * 17	认证审核中
+   * 18	认证审核驳回
+   * 19	认证审核通过
+   * 20	认证审核最终失败（不能再修改）
+   * 21	创建备案审核单失败
+   * 22	备案平台审核中
+   * 23	备案平台审核驳回
+   * 24	备案管局审核中
+   * 25	管局审核驳回
+   * 26	认证及备案完成
+   * 27	流程已过期
+   * 28	流程已终止
+   * 29	备案已撤回
+   */
+  @XStreamAlias("procedure_status")
+  private Integer procedureStatus;
+
+  //endregion
+
+  /**
+   * 原始通知内容
+   */
+  private String context;
+
+  //endregion
+
   /**
    * 快速创建的小程序appId，已弃用，未来将删除
    *
@@ -277,7 +321,9 @@ public static WxOpenXmlMessage fromEncryptedXml(String encryptedXml, WxOpenConfi
     WxOpenCryptUtil cryptUtil = new WxOpenCryptUtil(wxOpenConfigStorage);
     String plainText = cryptUtil.decryptXml(msgSignature, timestamp, nonce, encryptedXml);
     log.debug("解密后的原始xml消息内容：{}", plainText);
-    return fromXml(plainText);
+    WxOpenXmlMessage wxOpenXmlMessage = fromXml(plainText);
+    wxOpenXmlMessage.setContext(plainText);
+    return wxOpenXmlMessage;
   }
 
   public static WxMpXmlMessage fromEncryptedMpXml(String encryptedXml, WxOpenConfigStorage wxOpenConfigStorage,
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenGetAllCategoriesByTypeResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenGetAllCategoriesByTypeResult.java
new file mode 100644
index 0000000000..00cefeb37c
--- /dev/null
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenGetAllCategoriesByTypeResult.java
@@ -0,0 +1,153 @@
+package me.chanjar.weixin.open.bean.result;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 获取所有类目
+ * author 痴货
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+public class WxOpenGetAllCategoriesByTypeResult extends WxOpenResult {
+
+  private static final long serialVersionUID = -2845321894615646115L;
+
+  /**
+   * 类目信息列表
+   */
+  @SerializedName("categories_list")
+  private CategoriesList categorieslist;
+
+  @Getter
+  @Setter
+  @NoArgsConstructor
+  public static class CategoriesList implements Serializable {
+
+    private static final long serialVersionUID = -2845321894615646115L;
+
+    /**
+     * 类目信息
+     */
+    @SerializedName("categories")
+    private List<Categories> categories;
+  }
+
+  @Getter
+  @Setter
+  @NoArgsConstructor
+  public static class Categories implements Serializable {
+
+    private static final long serialVersionUID = -284532256461546115L;
+
+    /**
+     * 类目 ID
+     */
+    @SerializedName("id")
+    private Integer id;
+
+    /**
+     * 类目名称
+     */
+    @SerializedName("name")
+    private String name;
+
+    /**
+     * 类目层级
+     */
+    @SerializedName("level")
+    private Integer level;
+
+    /**
+     * 父类目 ID
+     */
+    @SerializedName("father")
+    private Integer father;
+
+    /**
+     * 子类目 ID
+     */
+    @SerializedName("children")
+    private List<Integer> children;
+
+    /**
+     * 是否敏感类目（1 为敏感类目，需要提供相应资质审核；0 为非敏感类目，无需审核）
+     */
+    @SerializedName("sensitive_type")
+    private Integer sensitiveType;
+
+    /**
+     * sensitive_type 为 1 的类目需要提供的资质证明
+     */
+    @SerializedName("qualify")
+    private Qualify qualify;
+
+    /**
+     * 类目权限范围
+     */
+    @SerializedName("scope")
+    private String scope;
+
+  }
+
+  @Getter
+  @Setter
+  @NoArgsConstructor
+  public static class Qualify implements Serializable {
+
+    private static final long serialVersionUID = -2841894318945616115L;
+
+    /**
+     * 资质证明列表
+     */
+    @SerializedName("exter_list")
+    private List<Exter> exterList;
+
+    /**
+     * 备注
+     */
+    @SerializedName("remark")
+    private String remark;
+
+  }
+
+  @Getter
+  @Setter
+  @NoArgsConstructor
+  public static class Exter implements Serializable {
+
+    private static final long serialVersionUID = -2841894318945616115L;
+
+    @SerializedName("inner_list")
+    private List<Inner> innerList;
+
+  }
+
+  @Getter
+  @Setter
+  @NoArgsConstructor
+  public static class Inner implements Serializable {
+
+    private static final long serialVersionUID = -15646131313516531L;
+
+    /**
+     * 资质文件名称
+     */
+    @SerializedName("name")
+    private String name;
+
+    /**
+     * 资质文件示例
+     */
+    @SerializedName("url")
+    private String url;
+
+  }
+
+}
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaEmbeddedListResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaEmbeddedListResult.java
new file mode 100644
index 0000000000..258a2630fa
--- /dev/null
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenMaEmbeddedListResult.java
@@ -0,0 +1,43 @@
+package me.chanjar.weixin.open.bean.result;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import me.chanjar.weixin.open.bean.ma.WxOpenMaEmbedded;
+import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder;
+
+import java.util.List;
+
+/**
+ * 获取半屏小程序调用列表返回值
+ *
+ * @author Yuan
+ * @version 1.0.0
+ * @date 2024-12-04 18:06:40
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class WxOpenMaEmbeddedListResult extends WxOpenResult {
+  private static final long serialVersionUID = -6484320771244602727L;
+
+  /**
+   * 半屏小程序列表
+   */
+  @SerializedName("wxa_embedded_list")
+  private List<WxOpenMaEmbedded> embeddedList;
+
+  /**
+   * 授权方式,0表示需要管理员确认，1表示自动通过，2表示自动拒绝
+   */
+  @SerializedName("embedded_flag")
+  private Integer embeddedFlag;
+
+  @Override
+  public String toString() {
+    return WxOpenGsonBuilder.create().toJson(this);
+  }
+
+  public String toJson() {
+    return WxOpenGsonBuilder.create().toJson(this);
+  }
+}
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenVersioninfoResult.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenVersioninfoResult.java
index 30bf9127c9..ae79d49589 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenVersioninfoResult.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/result/WxOpenVersioninfoResult.java
@@ -5,9 +5,6 @@
 import lombok.EqualsAndHashCode;
 import me.chanjar.weixin.open.util.json.WxOpenGsonBuilder;
 
-import java.io.Serializable;
-import java.util.List;
-
 /**
  * 小程序版本信息
  *
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/shoppingOrders/ShoppingInfoVerifyUpload.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/shoppingOrders/ShoppingInfoVerifyUpload.java
index 30b778f6f0..325ab65b00 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/shoppingOrders/ShoppingInfoVerifyUpload.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/bean/shoppingOrders/ShoppingInfoVerifyUpload.java
@@ -7,7 +7,6 @@
 import lombok.NoArgsConstructor;
 
 import java.io.Serializable;
-import java.util.List;
 
 @Data
 @Builder
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutor.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutor.java
index 4812dd325c..17c7906c5a 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutor.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutor.java
@@ -1,11 +1,15 @@
 package me.chanjar.weixin.open.executor;
 
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
 import me.chanjar.weixin.open.bean.CommonUploadMultiParam;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.ResponseHandler;
+import okhttp3.OkHttpClient;
 
 import java.io.IOException;
 
@@ -33,15 +37,19 @@ public void execute(String uri, CommonUploadMultiParam data, ResponseHandler<Str
    * @param requestHttp 请求信息
    * @return 执行器
    */
-  @SuppressWarnings({"rawtypes", "unchecked"})
-  public static RequestExecutor<String, CommonUploadMultiParam> create(RequestHttp requestHttp) {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<String, CommonUploadMultiParam> create(RequestHttp<?, ?> requestHttp) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new CommonUploadMultiRequestExecutorApacheImpl(requestHttp);
+        return new CommonUploadMultiRequestExecutorApacheImpl(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp);
       case JODD_HTTP:
-        return new CommonUploadMultiRequestExecutorJoddHttpImpl(requestHttp);
+        return new CommonUploadMultiRequestExecutorJoddHttpImpl((RequestHttp<HttpConnectionProvider, ProxyInfo>) requestHttp);
       case OK_HTTP:
-        return new CommonUploadMultiRequestExecutorOkHttpImpl(requestHttp);
+        return new CommonUploadMultiRequestExecutorOkHttpImpl((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp);
+      case HTTP_COMPONENTS:
+        return new CommonUploadMultiRequestExecutorHttpComponentsImpl(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp);
       default:
         throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutorApacheImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutorApacheImpl.java
index 2d386ea5d6..5717ded51e 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutorApacheImpl.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutorApacheImpl.java
@@ -2,17 +2,16 @@
 
 import lombok.Getter;
 import me.chanjar.weixin.common.bean.CommonUploadData;
-import me.chanjar.weixin.open.bean.CommonUploadMultiParam;
 import me.chanjar.weixin.common.bean.CommonUploadParam;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler;
-import org.apache.http.Consts;
+import me.chanjar.weixin.open.bean.CommonUploadMultiParam;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.entity.ContentType;
 import org.apache.http.entity.mime.HttpMultipartMode;
@@ -24,6 +23,7 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
 import java.util.List;
 
 /**
@@ -50,7 +50,7 @@ public String execute(String uri, CommonUploadMultiParam param, WxType wxType) t
       List<CommonUploadMultiParam.NormalParam> normalParams = param.getNormalParams();
       if (!CollectionUtils.isEmpty(normalParams)) {
         for (CommonUploadMultiParam.NormalParam normalParam : normalParams) {
-          entity.addPart(normalParam.getName(), new StringBody(normalParam.getValue(), ContentType.create("multipart/form-data", Consts.UTF_8)));
+          entity.addPart(normalParam.getName(), new StringBody(normalParam.getValue(), ContentType.MULTIPART_FORM_DATA.withCharset(StandardCharsets.UTF_8)));
         }
       }
 
@@ -64,19 +64,15 @@ public String execute(String uri, CommonUploadMultiParam param, WxType wxType) t
 
       httpPost.setEntity(entity.build());
     }
-    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
-      String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
-      if (responseContent == null || responseContent.isEmpty()) {
-        throw new WxErrorException(String.format("上传失败，服务器响应空 url:%s param:%s", uri, param));
-      }
-      WxError error = WxError.fromJson(responseContent, wxType);
-      if (error.getErrorCode() != 0) {
-        throw new WxErrorException(error);
-      }
-      return responseContent;
-    } finally {
-      httpPost.releaseConnection();
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    if (StringUtils.isEmpty(responseContent)) {
+      throw new WxErrorException(String.format("上传失败，服务器响应空 url:%s param:%s", uri, param));
+    }
+    WxError error = WxError.fromJson(responseContent, wxType);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
     }
+    return responseContent;
   }
 
   /**
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutorHttpComponentsImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutorHttpComponentsImpl.java
new file mode 100644
index 0000000000..98bf2e7541
--- /dev/null
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutorHttpComponentsImpl.java
@@ -0,0 +1,89 @@
+package me.chanjar.weixin.open.executor;
+
+import lombok.Getter;
+import me.chanjar.weixin.common.bean.CommonUploadData;
+import me.chanjar.weixin.common.bean.CommonUploadParam;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler;
+import me.chanjar.weixin.open.bean.CommonUploadMultiParam;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.entity.mime.HttpMultipartMode;
+import org.apache.hc.client5.http.entity.mime.InputStreamBody;
+import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
+import org.apache.hc.client5.http.entity.mime.StringBody;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.HttpHost;
+import org.springframework.util.CollectionUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+/**
+ * @author altusea
+ */
+public class CommonUploadMultiRequestExecutorHttpComponentsImpl extends CommonUploadMultiRequestExecutor<CloseableHttpClient, HttpHost> {
+
+  public CommonUploadMultiRequestExecutorHttpComponentsImpl(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
+
+  @Override
+  public String execute(String uri, CommonUploadMultiParam param, WxType wxType) throws WxErrorException, IOException {
+    HttpPost httpPost = new HttpPost(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpPost.setConfig(config);
+    }
+    if (param != null) {
+      MultipartEntityBuilder entity = MultipartEntityBuilder.create();
+
+      List<CommonUploadMultiParam.NormalParam> normalParams = param.getNormalParams();
+      if (!CollectionUtils.isEmpty(normalParams)) {
+        for (CommonUploadMultiParam.NormalParam normalParam : normalParams) {
+          entity.addPart(normalParam.getName(), new StringBody(normalParam.getValue(), ContentType.create("multipart/form-data", StandardCharsets.UTF_8)));
+        }
+      }
+
+      CommonUploadParam uploadParam = param.getUploadParam();
+      if (uploadParam != null) {
+        CommonUploadData data = uploadParam.getData();
+        InnerStreamBody part = new InnerStreamBody(data.getInputStream(), ContentType.DEFAULT_BINARY, data.getFileName(), data.getLength());
+        entity.addPart(uploadParam.getName(), part)
+          .setMode(HttpMultipartMode.EXTENDED);
+      }
+
+      httpPost.setEntity(entity.build());
+    }
+    String responseContent = requestHttp.getRequestHttpClient().execute(httpPost, Utf8ResponseHandler.INSTANCE);
+    if (StringUtils.isEmpty(responseContent)) {
+      throw new WxErrorException(String.format("上传失败，服务器响应空 url:%s param:%s", uri, param));
+    }
+    WxError error = WxError.fromJson(responseContent, wxType);
+    if (error.getErrorCode() != 0) {
+      throw new WxErrorException(error);
+    }
+    return responseContent;
+  }
+
+  /**
+   * 内部流 请求体
+   */
+  @Getter
+  public static class InnerStreamBody extends InputStreamBody {
+
+    private final long contentLength;
+
+    public InnerStreamBody(final InputStream in, final ContentType contentType, final String filename, long contentLength) {
+      super(in, contentType, filename);
+      this.contentLength = contentLength;
+    }
+  }
+}
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutorJoddHttpImpl.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutorJoddHttpImpl.java
index 1650c16740..8b2e801e51 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutorJoddHttpImpl.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/CommonUploadMultiRequestExecutorJoddHttpImpl.java
@@ -9,13 +9,12 @@
 import lombok.Getter;
 import lombok.SneakyThrows;
 import me.chanjar.weixin.common.bean.CommonUploadData;
-import me.chanjar.weixin.open.bean.CommonUploadMultiParam;
 import me.chanjar.weixin.common.bean.CommonUploadParam;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestHttp;
-import org.apache.http.Consts;
+import me.chanjar.weixin.open.bean.CommonUploadMultiParam;
 import org.apache.http.entity.ContentType;
 import org.apache.http.entity.mime.content.StringBody;
 import org.springframework.util.CollectionUtils;
@@ -47,7 +46,7 @@ public String execute(String uri, CommonUploadMultiParam param, WxType wxType) t
     List<CommonUploadMultiParam.NormalParam> normalParams = param.getNormalParams();
     if (!CollectionUtils.isEmpty(normalParams)) {
       for (CommonUploadMultiParam.NormalParam normalParam : normalParams) {
-        request.form(normalParam.getName(), new StringBody(normalParam.getValue(), ContentType.create("multipart/form-data", Consts.UTF_8)));
+        request.form(normalParam.getName(), new StringBody(normalParam.getValue(), ContentType.MULTIPART_FORM_DATA.withCharset(StandardCharsets.UTF_8)));
       }
     }
 
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/GenericUploadRequestExecutor.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/GenericUploadRequestExecutor.java
index e2d43a96a8..950028176c 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/GenericUploadRequestExecutor.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/GenericUploadRequestExecutor.java
@@ -1,6 +1,5 @@
 package me.chanjar.weixin.open.executor;
 
-import com.google.common.io.Files;
 import jodd.http.HttpConnectionProvider;
 import jodd.http.HttpRequest;
 import jodd.http.HttpResponse;
@@ -24,7 +23,6 @@
 import org.apache.http.entity.mime.MultipartEntityBuilder;
 import org.apache.http.impl.client.CloseableHttpClient;
 
-import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
@@ -133,11 +131,7 @@ public String execute(String uri, InputStream data, WxType wxType) throws WxErro
       bodyRequest.setEntity(entity);
       bodyRequest.setHeader("Content-Type", ContentType.MULTIPART_FORM_DATA.toString());
 
-      try (CloseableHttpResponse response = getRequestHttp().getRequestHttpClient().execute(bodyRequest)) {
-        return Utf8ResponseHandler.INSTANCE.handleResponse(response);
-      } finally {
-        bodyRequest.releaseConnection();
-      }
+      return getRequestHttp().getRequestHttpClient().execute(bodyRequest, Utf8ResponseHandler.INSTANCE);
     }
   }
 
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/MaQrCodeApacheHttpRequestExecutor.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/MaQrCodeApacheHttpRequestExecutor.java
index c95748f8a1..fa048df9a3 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/MaQrCodeApacheHttpRequestExecutor.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/MaQrCodeApacheHttpRequestExecutor.java
@@ -28,7 +28,7 @@
  * created on  2018-09-13
  */
 public class MaQrCodeApacheHttpRequestExecutor extends MaQrCodeRequestExecutor<CloseableHttpClient, HttpHost> {
-  public MaQrCodeApacheHttpRequestExecutor(RequestHttp requestHttp) {
+  public MaQrCodeApacheHttpRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
     super(requestHttp);
   }
 
@@ -61,8 +61,6 @@ public File execute(String uri, WxMaQrcodeParam qrcodeParam, WxType wxType) thro
         }
       }
       return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg");
-    } finally {
-      httpGet.releaseConnection();
     }
   }
 }
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/MaQrCodeHttpComponentsRequestExecutor.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/MaQrCodeHttpComponentsRequestExecutor.java
new file mode 100644
index 0000000000..e4682a7143
--- /dev/null
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/MaQrCodeHttpComponentsRequestExecutor.java
@@ -0,0 +1,65 @@
+package me.chanjar.weixin.open.executor;
+
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.fs.FileUtils;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import me.chanjar.weixin.common.util.http.hc.InputStreamResponseHandler;
+import me.chanjar.weixin.common.util.http.hc.Utf8ResponseHandler;
+import me.chanjar.weixin.open.bean.ma.WxMaQrcodeParam;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hc.client5.http.ClientProtocolException;
+import org.apache.hc.client5.http.classic.methods.HttpGet;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLEncoder;
+import java.util.UUID;
+
+public class MaQrCodeHttpComponentsRequestExecutor extends MaQrCodeRequestExecutor<CloseableHttpClient, HttpHost> {
+  public MaQrCodeHttpComponentsRequestExecutor(RequestHttp<CloseableHttpClient, HttpHost> requestHttp) {
+    super(requestHttp);
+  }
+
+  @Override
+  public File execute(String uri, WxMaQrcodeParam qrcodeParam, WxType wxType) throws WxErrorException, IOException {
+    if (qrcodeParam != null && StringUtils.isNotBlank(qrcodeParam.getPagePath())) {
+      if (uri.indexOf('?') == -1) {
+        uri += '?';
+      }
+      uri += uri.endsWith("?")
+        ? "path=" + URLEncoder.encode(qrcodeParam.getRequestPath(), "UTF-8")
+        : "&path=" + URLEncoder.encode(qrcodeParam.getRequestPath(), "UTF-8");
+    }
+
+    HttpGet httpGet = new HttpGet(uri);
+    if (requestHttp.getRequestHttpProxy() != null) {
+      RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+      httpGet.setConfig(config);
+    }
+
+    try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpGet);
+         InputStream inputStream = InputStreamResponseHandler.INSTANCE.handleResponse(response);) {
+      Header[] contentTypeHeader = response.getHeaders("Content-Type");
+      if (contentTypeHeader != null && contentTypeHeader.length > 0) {
+        // 出错
+        if (ContentType.TEXT_PLAIN.getMimeType().equals(ContentType.parse(contentTypeHeader[0].getValue()).getMimeType())) {
+          String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
+          throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp));
+        }
+      }
+      return FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), "jpg");
+    } catch (HttpException httpException) {
+      throw new ClientProtocolException(httpException.getMessage(), httpException);
+    }
+  }
+}
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/MaQrCodeJoddHttpRequestExecutor.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/MaQrCodeJoddHttpRequestExecutor.java
index 5eddf762b1..415a5c7b24 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/MaQrCodeJoddHttpRequestExecutor.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/MaQrCodeJoddHttpRequestExecutor.java
@@ -5,7 +5,6 @@
 import jodd.http.HttpResponse;
 import jodd.http.ProxyInfo;
 import jodd.net.MimeTypes;
-import jodd.util.StringPool;
 import me.chanjar.weixin.common.enums.WxType;
 import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
@@ -27,7 +26,7 @@
  * created on  2018-09-13
  */
 public class MaQrCodeJoddHttpRequestExecutor extends MaQrCodeRequestExecutor<HttpConnectionProvider, ProxyInfo> {
-  public MaQrCodeJoddHttpRequestExecutor(RequestHttp requestHttp) {
+  public MaQrCodeJoddHttpRequestExecutor(RequestHttp<HttpConnectionProvider, ProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/MaQrCodeOkhttpRequestExecutor.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/MaQrCodeOkhttpRequestExecutor.java
index 77816949d6..e30ceeb973 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/MaQrCodeOkhttpRequestExecutor.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/MaQrCodeOkhttpRequestExecutor.java
@@ -23,7 +23,7 @@
  * created on  2018-09-13
  */
 public class MaQrCodeOkhttpRequestExecutor extends MaQrCodeRequestExecutor<OkHttpClient, OkHttpProxyInfo> {
-  public MaQrCodeOkhttpRequestExecutor(RequestHttp requestHttp) {
+  public MaQrCodeOkhttpRequestExecutor(RequestHttp<OkHttpClient, OkHttpProxyInfo> requestHttp) {
     super(requestHttp);
   }
 
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/MaQrCodeRequestExecutor.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/MaQrCodeRequestExecutor.java
index d37c31d05e..000845b716 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/MaQrCodeRequestExecutor.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/executor/MaQrCodeRequestExecutor.java
@@ -3,13 +3,16 @@
 import java.io.File;
 import java.io.IOException;
 
+import jodd.http.HttpConnectionProvider;
+import jodd.http.ProxyInfo;
 import me.chanjar.weixin.common.enums.WxType;
-import me.chanjar.weixin.common.error.WxError;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.util.http.RequestExecutor;
 import me.chanjar.weixin.common.util.http.RequestHttp;
 import me.chanjar.weixin.common.util.http.ResponseHandler;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
 import me.chanjar.weixin.open.bean.ma.WxMaQrcodeParam;
+import okhttp3.OkHttpClient;
 
 /**
  * 获得小程序体验QrCode图片 请求执行器.
@@ -20,7 +23,7 @@
 public abstract class MaQrCodeRequestExecutor<H, P> implements RequestExecutor<File, WxMaQrcodeParam> {
   protected RequestHttp<H, P> requestHttp;
 
-  public MaQrCodeRequestExecutor(RequestHttp requestHttp) {
+  public MaQrCodeRequestExecutor(RequestHttp<H, P> requestHttp) {
     this.requestHttp = requestHttp;
   }
 
@@ -29,16 +32,21 @@ public void execute(String uri, WxMaQrcodeParam data, ResponseHandler<File> hand
     handler.handle(this.execute(uri, data, wxType));
   }
 
-  public static RequestExecutor<File, WxMaQrcodeParam> create(RequestHttp requestHttp) throws WxErrorException {
+  @SuppressWarnings("unchecked")
+  public static RequestExecutor<File, WxMaQrcodeParam> create(RequestHttp<?, ?> requestHttp) {
     switch (requestHttp.getRequestType()) {
       case APACHE_HTTP:
-        return new MaQrCodeApacheHttpRequestExecutor(requestHttp);
+        return new MaQrCodeApacheHttpRequestExecutor(
+          (RequestHttp<org.apache.http.impl.client.CloseableHttpClient, org.apache.http.HttpHost>) requestHttp);
       case JODD_HTTP:
-        return new MaQrCodeJoddHttpRequestExecutor(requestHttp);
+        return new MaQrCodeJoddHttpRequestExecutor((RequestHttp<HttpConnectionProvider, ProxyInfo>) requestHttp);
       case OK_HTTP:
-        return new MaQrCodeOkhttpRequestExecutor(requestHttp);
+        return new MaQrCodeOkhttpRequestExecutor((RequestHttp<OkHttpClient, OkHttpProxyInfo>) requestHttp);
+      case HTTP_COMPONENTS:
+        return new MaQrCodeHttpComponentsRequestExecutor(
+          (RequestHttp<org.apache.hc.client5.http.impl.classic.CloseableHttpClient, org.apache.hc.core5.http.HttpHost>) requestHttp);
       default:
-        throw new WxErrorException("不支持的http框架");
+        throw new IllegalArgumentException("不支持的http执行器类型：" + requestHttp.getRequestType());
     }
   }
 
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/WxOpenCryptUtil.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/WxOpenCryptUtil.java
index e6c8ce992d..ee1ada8dbb 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/WxOpenCryptUtil.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/WxOpenCryptUtil.java
@@ -1,7 +1,5 @@
 package me.chanjar.weixin.open.util;
 
-import com.google.common.base.CharMatcher;
-import com.google.common.io.BaseEncoding;
 import me.chanjar.weixin.open.api.WxOpenConfigStorage;
 import org.apache.commons.lang3.StringUtils;
 
diff --git a/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenAuthorizerListResultGsonAdapter.java b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenAuthorizerListResultGsonAdapter.java
index 2128839c23..cda1101793 100644
--- a/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenAuthorizerListResultGsonAdapter.java
+++ b/weixin-java-open/src/main/java/me/chanjar/weixin/open/util/json/WxOpenAuthorizerListResultGsonAdapter.java
@@ -24,10 +24,9 @@ public WxOpenAuthorizerListResult deserialize(JsonElement jsonElement, Type type
     wxOpenAuthorizerListResult.setTotalCount(GsonHelper.getInteger(jsonObject, "total_count").intValue());
 
     List<Map<String, String>> list = new ArrayList<>();
-    Iterator<JsonElement> jsonElementIterator = jsonObject.getAsJsonArray("list").iterator();
 
-    while (jsonElementIterator.hasNext()) {
-      JsonObject authorizer = jsonElementIterator.next().getAsJsonObject();
+    for (JsonElement element : jsonObject.getAsJsonArray("list")) {
+      JsonObject authorizer = element.getAsJsonObject();
       Map<String, String> authorizerMap = new HashMap<>(10);
 
       authorizerMap.put(AUTHORIZER_APPID, GsonHelper.getString(authorizer, AUTHORIZER_APPID));
diff --git a/weixin-java-pay/CONNECTION_POOL.md b/weixin-java-pay/CONNECTION_POOL.md
new file mode 100644
index 0000000000..2b2569adcb
--- /dev/null
+++ b/weixin-java-pay/CONNECTION_POOL.md
@@ -0,0 +1,67 @@
+# HTTP连接池功能说明
+
+## 概述
+
+`WxPayServiceApacheHttpImpl` 现在支持HTTP连接池功能，可以显著提高高并发场景下的性能表现。
+
+## 主要改进
+
+1. **连接复用**: 不再为每个请求创建新的HttpClient实例，而是复用连接池中的连接
+2. **性能提升**: 减少连接建立和销毁的开销，提高吞吐量
+3. **资源优化**: 合理控制并发连接数，避免资源浪费
+4. **SSL支持**: 同时支持普通HTTP和SSL连接的连接池
+
+## 配置说明
+
+### 默认配置
+```java
+WxPayConfig config = new WxPayConfig();
+// 默认配置：
+// maxConnTotal = 20        (最大连接数)
+// maxConnPerRoute = 10     (每个路由最大连接数)
+```
+
+### 自定义配置
+```java
+WxPayConfig config = new WxPayConfig();
+config.setMaxConnTotal(50);      // 设置最大连接数
+config.setMaxConnPerRoute(20);   // 设置每个路由最大连接数
+```
+
+## 使用方式
+
+连接池功能是自动启用的，无需额外配置：
+
+```java
+// 1. 配置微信支付
+WxPayConfig config = new WxPayConfig();
+config.setAppId("your-app-id");
+config.setMchId("your-mch-id");
+config.setMchKey("your-mch-key");
+
+// 2. 创建支付服务（连接池自动启用）
+WxPayServiceApacheHttpImpl payService = new WxPayServiceApacheHttpImpl();
+payService.setConfig(config);
+
+// 3. 正常使用，所有HTTP请求都会使用连接池
+WxPayUnifiedOrderResult result = payService.unifiedOrder(request);
+```
+
+## 向后兼容性
+
+- 此功能完全向后兼容，现有代码无需修改
+- 如果不设置连接池参数，将使用默认配置
+- 支持原有的HttpClientBuilderCustomizer自定义功能
+
+## 注意事项
+
+1. 连接池中的HttpClient实例会被复用，不要手动关闭
+2. SSL连接和普通连接使用不同的连接池
+3. 连接池参数建议根据实际并发量调整
+4. 代理配置仍然正常工作
+
+## 性能建议
+
+- 对于高并发应用，建议适当增加`maxConnTotal`和`maxConnPerRoute`
+- 监控连接池使用情况，避免连接数不足导致的阻塞
+- 在容器环境中，注意连接池配置与容器资源限制的平衡
\ No newline at end of file
diff --git a/weixin-java-pay/pom.xml b/weixin-java-pay/pom.xml
index 4d6c046228..7fa82053b5 100644
--- a/weixin-java-pay/pom.xml
+++ b/weixin-java-pay/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <groupId>com.github.binarywang</groupId>
     <artifactId>wx-java</artifactId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
@@ -34,6 +34,11 @@
       <artifactId>jodd-util</artifactId>
       <version>6.1.0</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.httpcomponents.client5</groupId>
+      <artifactId>httpclient5</artifactId>
+      <scope>provided</scope>
+    </dependency>
 
     <dependency>
       <groupId>org.apache.commons</groupId>
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyconfirm/ApplySubjectConfirmCreateRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyconfirm/ApplySubjectConfirmCreateRequest.java
index b95061461c..d77522ecce 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyconfirm/ApplySubjectConfirmCreateRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyconfirm/ApplySubjectConfirmCreateRequest.java
@@ -119,8 +119,8 @@ public static class ApplySubConfirmIdentificationInfo implements Serializable {
      * IDENTIFICATION_TYPE_TAIWAN_RESIDENT：台湾居民证
      * 示例值：IDENTIFICATION_TYPE_IDCARD
      */
-    @SerializedName("id_doc_type")
-    private IdTypeEnum idDocType;
+    @SerializedName("identification_type")
+    private IdTypeEnum identificationType;
 
     /**
      * 法定代表人说明函
@@ -414,13 +414,13 @@ public static class ApplySubConfirmSubjectInfo implements Serializable {
      * 若未传入将默认填写：false。
      * 示例值：true
      */
-    @SerializedName("finance_institution")
+    @SerializedName("is_finance_institution")
     private Boolean financeInstitution;
 
     /**
      * 营业执照
      */
-    @SerializedName("business_license_info")
+    @SerializedName("business_licence_info")
     private ApplySubConfirmBusinessLicenseInfo businessLicenseInfo;
     /**
      * 登记证书
@@ -736,8 +736,8 @@ public static class ApplySubConfirmSpecialOperationList implements Serializable
        * 参看微信支付提供的特殊行业id对照表
        * 示例值：100
        */
-      @SerializedName("finance_type")
-      private Integer financeType;
+      @SerializedName("category_id")
+      private Integer categoryId;
 
       /**
        * 行业经营许可证资质照片
@@ -791,29 +791,10 @@ public static class ApplySubConfirmAdditionInfo implements Serializable {
     private static final long serialVersionUID = 1L;
 
     /**
-     * 法人开户承诺函
-     */
-    @SerializedName("legal_person_commitment")
-    private String legalPersonCommitment;
-
-    /**
-     * 法人开户意愿视频
+     * 待确认商户号列表
      */
-    @SerializedName("legal_person_video")
-    private String legalPersonVideo;
-
-    /**
-     * 补充材料
-     */
-    @SerializedName("business_addition_pics")
-    private List<String> businessAdditionPics;
-
-    /**
-     * 补充说明
-     */
-    @SerializedName("business_addition_msg")
-    private String businessAdditionMsg;
-
+    @SerializedName("confirm_mchid_list")
+    private List<String> confirmMchidList;
   }
 
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyconfirm/ApplySubjectConfirmMerchantStateQueryResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyconfirm/ApplySubjectConfirmMerchantStateQueryResult.java
index c155e1e6cd..1b5fc6eb7d 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyconfirm/ApplySubjectConfirmMerchantStateQueryResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyconfirm/ApplySubjectConfirmMerchantStateQueryResult.java
@@ -1,7 +1,6 @@
 package com.github.binarywang.wxpay.bean.applyconfirm;
 
 import com.github.binarywang.wxpay.bean.applyconfirm.enums.AuthorizeStateEnum;
-import com.github.binarywang.wxpay.bean.applyment.enums.ApplymentStateEnum;
 import com.google.gson.annotations.SerializedName;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyconfirm/ApplySubjectConfirmStateQueryResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyconfirm/ApplySubjectConfirmStateQueryResult.java
index 77ee4c51eb..18337e419c 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyconfirm/ApplySubjectConfirmStateQueryResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyconfirm/ApplySubjectConfirmStateQueryResult.java
@@ -1,6 +1,6 @@
 package com.github.binarywang.wxpay.bean.applyconfirm;
 
-import com.github.binarywang.wxpay.bean.applyment.enums.ApplymentStateEnum;
+import com.github.binarywang.wxpay.bean.applyconfirm.enums.ApplySubjectStateEnum;
 import com.google.gson.annotations.SerializedName;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
@@ -9,7 +9,6 @@
 import lombok.experimental.Accessors;
 
 import java.io.Serializable;
-import java.util.List;
 
 /**
  * 查询申请单状态返回对象信息
@@ -26,7 +25,7 @@ public class ApplySubjectConfirmStateQueryResult implements Serializable {
    * 申请单状态
    */
   @SerializedName("applyment_state")
-  private ApplymentStateEnum applymentState;
+  private ApplySubjectStateEnum applymentState;
   /**
    * 二维码图片
    */
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyconfirm/enums/ApplySubjectStateEnum.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyconfirm/enums/ApplySubjectStateEnum.java
new file mode 100644
index 0000000000..a0821706c2
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/applyconfirm/enums/ApplySubjectStateEnum.java
@@ -0,0 +1,42 @@
+package com.github.binarywang.wxpay.bean.applyconfirm.enums;
+
+/**
+ * 开户意愿申请单状态枚举类
+ *
+ * @author 潘安
+ */
+public enum ApplySubjectStateEnum {
+  /**
+   * 【审核中】，请耐心等待3~7个工作日，微信支付将会完成审核。
+   */
+  APPLYMENT_STATE_WAITTING_FOR_AUDIT,
+  /**
+   * 【编辑中】，可能提交申请发生了错误导致，可用同一个业务申请编号重新提交。
+   */
+  APPLYMENT_STATE_EDITTING,
+  /**
+   * 【待确认联系信息】，请扫描微信支付返回的二维码确认联系信息(此过程可修改超级管理员手机号)。
+   */
+  APPLYMENT_STATE_WAITTING_FOR_CONFIRM_CONTACT,
+  /**
+   * 【待账户验证】，请扫描微信支付返回的二维码在小程序端完成账户验证。
+   */
+  APPLYMENT_STATE_WAITTING_FOR_CONFIRM_LEGALPERSON,
+  /**
+   * 【审核通过】，请扫描微信支付返回的二维码在小程序端完成授权流程。
+   */
+  APPLYMENT_STATE_PASSED,
+  /**
+   * 【审核驳回】，请按照驳回原因修改申请资料，并更换业务申请编码，重新提交申请。
+   */
+  APPLYMENT_STATE_REJECTED,
+  /**
+   * 【已冻结】，可能是该主体已完成过入驻，请查看驳回原因，并通知驳回原因中指定的联系人扫描微信支付返回的二维码在小程序端完成授权流程。
+   */
+  APPLYMENT_STATE_FREEZED,
+  /**
+   * 【已作废】，表示申请单已被撤销，无需再对其进行操作。
+   */
+  APPLYMENT_STATE_CANCELED
+
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/BankAccountResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/BankAccountResult.java
index 5f67a2badf..44e2acb8cc 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/BankAccountResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/BankAccountResult.java
@@ -2,8 +2,6 @@
 
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import lombok.Getter;
-import lombok.Setter;
 
 import java.io.Serializable;
 import java.util.List;
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/BankBranchesResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/BankBranchesResult.java
index 72cc4f6a76..a0ee6d3d99 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/BankBranchesResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/BankBranchesResult.java
@@ -144,7 +144,10 @@ public class BankBranchesResult implements Serializable {
 
   @Getter
   @Setter
-  public static class BankBranch {
+  public static class BankBranch implements Serializable {
+
+    private static final long serialVersionUID = -3500020131951579476L;
+
     /**
      * <pre>
      * 字段名：开户银行支行名称
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/BankInfo.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/BankInfo.java
index 89756b07d5..b9ea2c3348 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/BankInfo.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/BankInfo.java
@@ -2,8 +2,8 @@
 
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import lombok.Getter;
-import lombok.Setter;
+
+import java.io.Serializable;
 
 /**
  * 银行信息
@@ -12,7 +12,10 @@
  * created on  2022/5/12
  **/
 @Data
-public class BankInfo {
+public class BankInfo implements Serializable {
+
+  private static final long serialVersionUID = 1L;
+
   /**
    * 银行别名
    */
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/BankingResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/BankingResult.java
index 407ad5fc55..1d3a48c200 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/BankingResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/BankingResult.java
@@ -43,7 +43,10 @@ public class BankingResult implements Serializable {
 
   @Getter
   @Setter
-  public static class Link {
+  public static class Link implements Serializable {
+
+    private static final long serialVersionUID = -8372812998971715894L;
+
     /**
      * 下一页链接
      */
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/CitiesResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/CitiesResult.java
index b5bf87c816..b6914ee814 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/CitiesResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/CitiesResult.java
@@ -47,7 +47,10 @@ public class CitiesResult implements Serializable {
 
   @Getter
   @Setter
-  public static class CityInfo {
+  public static class CityInfo implements Serializable {
+
+    private static final long serialVersionUID = -6089905695087974693L;
+
     /**
      * <pre>
      * 字段名：城市名称
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/PageLink.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/PageLink.java
index 419cdc3c94..d8431f6709 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/PageLink.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/PageLink.java
@@ -2,11 +2,8 @@
 
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import lombok.Getter;
-import lombok.Setter;
 
 import java.io.Serializable;
-import java.util.List;
 
 /**
  * 支行列表
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/ProvincesResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/ProvincesResult.java
index 6525fc1c91..162c976347 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/ProvincesResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/bank/ProvincesResult.java
@@ -47,7 +47,9 @@ public class ProvincesResult implements Serializable {
 
   @Getter
   @Setter
-  public static class ProvinceInfo {
+  public static class ProvinceInfo implements Serializable {
+
+    private static final long serialVersionUID = -4118613374545722650L;
 
     /**
      * <pre>
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/complaint/ComplaintDetailResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/complaint/ComplaintDetailResult.java
index 157e095bba..f8562dce39 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/complaint/ComplaintDetailResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/complaint/ComplaintDetailResult.java
@@ -327,4 +327,141 @@ public static class ServiceOrder implements Serializable {
    */
   @SerializedName("user_tag_list")
   private String[] userTagList;
+
+  /**
+   * <pre>
+   * 字段名：补充信息
+   * 是否必填：否
+   * 描述： 用在特定行业或场景下返回的补充信息
+   * </pre>
+   */
+  @SerializedName("additional_info")
+  private AdditionalInfo additionalInfo;
+
+  @Data
+  public static class AdditionalInfo implements Serializable {
+    private static final long serialVersionUID = 7917816070738944147L;
+
+    /**
+     * <pre>
+     * 字段名：补充信息类型
+     * 是否必填：否
+     * 描述： 补充信息类型
+     * 示例值：SHARE_POWER_TYPE: 充电宝投诉相关行业
+     * </pre>
+     */
+    @SerializedName("type")
+    private String type;
+
+    /**
+     * <pre>
+     * 字段名：充电宝投诉相关信息
+     * 是否必填：否
+     * 描述：当type为充电宝投诉相关时有值
+     * </pre>
+     */
+    @SerializedName("share_power_info")
+    private SharePowerInfo sharePowerInfo;
+
+    /**
+     * 充电宝投诉相关信息
+     */
+    @Data
+    public static class SharePowerInfo implements Serializable {
+      private static final long serialVersionUID = -2878382307459369354L;
+
+      /**
+       * <pre>
+       * 字段名：归还时间
+       * 是否必填：否
+       * 描述：遵循rfc3339标准格式，格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE，
+       *      yyyy-MM-DD表示年月日，T出现在字符串中，表示time元素的开头，
+       *      HH:mm:ss表示时分秒，
+       *      TIMEZONE表示时区（+08:00表示东八区时间，领先UTC 8小时，即北京时间）。
+       * 示例值：2015-05-20T13:29:35+08:00表示，北京时间2015年5月20日 13点29分35秒
+       * </pre>
+       */
+      @SerializedName("return_time")
+      private String returnTime;
+
+      /**
+       * <pre>
+       * 字段名：归还地点信息
+       * 是否必填：否
+       * 描述：  归还地点信息
+       * </pre>
+       */
+      @SerializedName("return_address_info")
+      private ReturnAddressInfo returnAddressInfo;
+
+      @Data
+      public static class ReturnAddressInfo implements Serializable {
+        private static final long serialVersionUID = -7649986542568217256L;
+
+        /**
+         * <pre>
+         * 字段名：归还地点
+         * 是否必填：否 string(256)
+         * 描述：归还地点
+         * </pre>
+         */
+        @SerializedName("return_address")
+        private String returnAddress;
+
+        /**
+         * <pre>
+         * 字段名：归还地点经度
+         * 是否必填：否 string(32)
+         * 描述：经度，字符串，范围为-180~180，负数表示西经。使用GCJ-02坐标系
+         * </pre>
+         */
+        @SerializedName("longitude")
+        private String longitude;
+
+        /**
+         * <pre>
+         * 字段名：归还地点纬度
+         * 是否必填：否 string(32)
+         * 描述：纬度，字符串，范围为-90~90，负数表示南纬。使用GCJ-02坐标系
+         * </pre>
+         */
+        @SerializedName("latitude")
+        private String latitude;
+      }
+
+      /**
+       * <pre>
+       * 字段名：是否归还同一柜机
+       * 是否必填：否
+       * 描述：用户声明是否将充电宝归还至与借取时同一柜机
+       * </pre>
+       */
+      @SerializedName("is_returned_to_same_machine")
+      private Boolean isReturnedToSameMachine;
+    }
+  }
+
+  /**
+   * <pre>
+   * 字段名：是否在平台协助中
+   * 是否必填：否
+   * 描述：标识当前投诉单是否正处在平台协助流程中。
+   * 注：在协助期间由微信支付客服为用户服务，期间商户向用户发送的留言用户不可见
+   * </pre>
+   */
+  @SerializedName("in_platform_service")
+  private Boolean inPlatformService;
+
+  /**
+   * <pre>
+   * 字段名：是否需即时服务用户
+   * 是否必填：否
+   * 描述：因用户诉求紧急度、用户界面差异等因素，部分投诉单建议商户更即时地响应用户诉求。
+   *      如此处标识为“是”，建议商户提升服务时效，给用户带来更好的体验
+   * </pre>
+   */
+  @SerializedName("need_immediate_service")
+  private Boolean needImmediateService;
+
+
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/complaint/ComplaintNotifyUrlResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/complaint/ComplaintNotifyUrlResult.java
index bc7e066d31..1b40affe94 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/complaint/ComplaintNotifyUrlResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/complaint/ComplaintNotifyUrlResult.java
@@ -1,13 +1,10 @@
 package com.github.binarywang.wxpay.bean.complaint;
 
 
-import com.github.binarywang.wxpay.bean.media.MarketingImageUploadResult;
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
-import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 
 import java.io.Serializable;
-import java.util.List;
 
 /**
  * 微信消费者投诉2.0
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/complaint/NegotiationHistoryResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/complaint/NegotiationHistoryResult.java
index 2da216446d..7c8738fe29 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/complaint/NegotiationHistoryResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/complaint/NegotiationHistoryResult.java
@@ -142,20 +142,30 @@ public static class ComplaintMedia implements Serializable {
      * 是否必填：是
      * 描述：
      * 当前投诉协商记录的操作类型，对应枚举：
-     * USER_CREATE_COMPLAINT：用户提交投诉
-     * USER_CONTINUE_COMPLAINT：用户继续投诉
-     * USER_RESPONSE：用户留言
-     * PLATFORM_RESPONSE：平台留言
-     * MERCHANT_RESPONSE：商户留言
-     * MERCHANT_CONFIRM_COMPLETE：商户申请结单
-     * COMPLAINT_FULL_REFUNDED：投诉单全额退款
-     * USER_CREATE_COMPLAINT_SYSTEM_MESSAGE：用户提交投诉系统通知
-     * COMPLAINT_FULL_REFUNDED_SYSTEM_MESSAGE：投诉单全额退款系统通知
-     * USER_CONTINUE_COMPLAINT_SYSTEM_MESSAGE：用户继续投诉系统通知
-     * MERCHANT_CONFIRM_COMPLETE_SYSTEM_MESSAGE：商户申请结单系统通知
-     * USER_REVOKE_COMPLAINT：用户主动撤诉（只存在于历史投诉单的协商历史中）
-     * PLATFORM_HELP_APPLICATION：平台问询
-     * USER_APPLY_PLATFORM_HELP：申请协助
+     * USER_CREATE_COMPLAINT: 用户提交投诉
+     * USER_CONTINUE_COMPLAINT: 用户继续投诉
+     * USER_RESPONSE: 用户留言
+     * PLATFORM_RESPONSE: 平台留言
+     * MERCHANT_RESPONSE: 商户留言
+     * MERCHANT_CONFIRM_COMPLETE: 商户申请结单
+     * USER_CREATE_COMPLAINT_SYSTEM_MESSAGE: 用户提交投诉系统通知
+     * COMPLAINT_FULL_REFUNDED_SYSTEM_MESSAGE: 投诉单发起全额退款系统通知
+     * USER_CONTINUE_COMPLAINT_SYSTEM_MESSAGE: 用户继续投诉系统通知
+     * USER_REVOKE_COMPLAINT: 用户主动撤诉（只存在于历史投诉单的协商历史中）
+     * USER_COMFIRM_COMPLAINT: 用户确认投诉解决（只存在于历史投诉单的协商历史中）
+     * PLATFORM_HELP_APPLICATION: 平台催办
+     * USER_APPLY_PLATFORM_HELP: 用户申请平台协助
+     * MERCHANT_APPROVE_REFUND: 商户同意退款申请
+     * MERCHANT_REFUSE_RERUND: 商户拒绝退款申请, 此时操作内容里展示拒绝原因
+     * USER_SUBMIT_SATISFACTION: 用户提交满意度调查结果,此时操作内容里会展示满意度分数
+     * SERVICE_ORDER_CANCEL: 服务订单已取消
+     * SERVICE_ORDER_COMPLETE: 服务订单已完成
+     * COMPLAINT_PARTIAL_REFUNDED_SYSTEM_MESSAGE: 投诉单发起部分退款系统通知
+     * COMPLAINT_REFUND_RECEIVED_SYSTEM_MESSAGE: 投诉单退款到账系统通知
+     * COMPLAINT_ENTRUSTED_REFUND_SYSTEM_MESSAGE: 投诉单受托退款系统通知
+     * USER_APPLY_PLATFORM_SERVICE: 用户申请平台协助
+     * USER_CANCEL_PLATFORM_SERVICE: 用户取消平台协助
+     * PLATFORM_SERVICE_FINISHED: 客服结束平台协助
      * </pre>
      */
     @SerializedName("operate_type")
@@ -179,11 +189,32 @@ public static class ComplaintMedia implements Serializable {
      * 描述：
      * 当前投诉协商记录提交的图片凭证（url格式），最多返回4张图片，url有效时间为1小时。如未查询到协商历史图片凭证，则返回空数组。
      * 注：本字段包含商户、微信支付客服在协商解决投诉时上传的图片凭证，若希望查看用户图片，请使用complaint_media_list字段并联系微信支付客服
+     * 注：此字段不包含用户提交的图片凭证，建议统一使用complaint_media_list字段接收和请求资料凭证，未来该字段将废弃
      * </pre>
      */
     @SerializedName("image_list")
     private List<String> imageList;
 
+    /**
+     * <pre>
+     * 字段名：用户申请平台协助原因
+     * 是否必填：否
+     * 描述：用户此次申请平台协助时选择的申请协助原因
+     * </pre>
+     */
+    @SerializedName("user_appy_platform_service_reason")
+    private String userApplyPlatformServiceReason;
+
+    /**
+     * <pre>
+     * 字段名：用户申请平台协助原因描述
+     * 是否必填：否
+     * 描述：用户此次申请平台协助时填写的具体申请协助原因描述
+     * </pre>
+     */
+    @SerializedName("user_appy_platform_service_reason_description")
+    private String userApplyPlatformServiceReasonDescription;
+
   }
 
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/complaint/ResponseRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/complaint/ResponseRequest.java
index 6f582b9301..470f2bed11 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/complaint/ResponseRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/complaint/ResponseRequest.java
@@ -94,4 +94,57 @@ public class ResponseRequest implements Serializable {
   @SerializedName("jump_url_text")
   private String jumpUrlText;
 
+  /**
+   * <pre>
+   * 字段名：跳转小程序信息
+   * 是否必填：否
+   * 描述：商户可在回复中附加小程序信息，引导用户跳转至商户客诉处理小程序。
+   * 注：配置小程序属于灰度功能，若有需要请联系对接的行业运营进行咨询。
+   * </pre>
+   */
+  @SerializedName("mini_program_jump_info")
+  private MiniProgramJumpInfo miniProgramJumpInfo;
+
+
+  /**
+   * 跳转小程序信息
+   */
+  @Data
+  public static class MiniProgramJumpInfo implements Serializable {
+    private static final long serialVersionUID = 1169503275787468380L;
+
+    /**
+     * <pre>
+     * 字段名：跳转小程序APPID
+     * 是否必填：是
+     * 描述：商户可在回复中附加小程序页面路径，引导用户跳转至商户服务工具页面。
+     *      该字段为小程序APPID。
+     * </pre>
+     */
+    @SerializedName("appid")
+    private String appId;
+
+    /**
+     * <pre>
+     * 字段名：跳转小程序页面PATH
+     * 是否必填：是
+     * 描述：商户可在回复中附加小程序页面路径，引导用户跳转至商户服务工具页面。
+     *      该字段为小程序路径。
+     * </pre>
+     */
+    @SerializedName("path")
+    private String path;
+
+    /**
+     * <pre>
+     * 字段名：跳转小程序页面名称
+     * 是否必填：是
+     * 描述：商户可在回复中附加小程序页面路径，引导用户跳转至商户服务工具页面。
+     *      该字段为商户可自定义的页面名称。
+     * </pre>
+     */
+    @SerializedName("text")
+    private String text;
+  }
+
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/complaint/UpdateRefundProgressRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/complaint/UpdateRefundProgressRequest.java
new file mode 100644
index 0000000000..79668bd0ce
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/complaint/UpdateRefundProgressRequest.java
@@ -0,0 +1,92 @@
+package com.github.binarywang.wxpay.bean.complaint;
+
+import com.google.gson.annotations.Expose;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 微信消费者投诉2.0
+ * 更新退款审批结果请求实体
+ *
+ * @author <a href="https://github.com/jackytse">jackytse</a>
+ * created on  2024-12-21
+ */
+@Data
+@Builder(builderMethodName = "newBuilder")
+@NoArgsConstructor
+@AllArgsConstructor
+public class UpdateRefundProgressRequest implements Serializable {
+  private static final long serialVersionUID = 6975811815225228118L;
+
+  /**
+   * <pre>
+   * 字段名：投诉单号
+   * 是否必填：是
+   * 描述：投诉单对应的投诉单号
+   * </pre>
+   */
+  @SerializedName("complaint_id")
+  @Expose
+  private String complaintId;
+
+  /**
+   * <pre>
+   * 字段名：审批动作
+   * 是否必填：是
+   * 描述：同意 或 拒绝
+   * 可选取值：
+   * REJECT: 拒绝退款
+   * APPROVE: 同意退款
+   * </pre>
+   */
+  @SerializedName("action")
+  private String action;
+
+  /**
+   * <pre>
+   * 字段名：预计发起退款时间
+   * 是否必填：否
+   * 描述：在同意退款时返回，预计将在多少个工作日内能发起退款, 0代表当天
+   * </pre>
+   */
+  @SerializedName("launch_refund_day")
+  private Integer launchRefundDay;
+
+  /**
+   * <pre>
+   * 字段名：拒绝退款原因
+   * 是否必填：否 string(200)
+   * 描述：在拒绝退款时返回拒绝退款的原因
+   * </pre>
+   */
+  @SerializedName("reject_reason")
+  private String rejectReason;
+
+  /**
+   * <pre>
+   * 字段名：拒绝退款的举证图片列表
+   * 是否必填：否
+   * 描述：在拒绝退款时，如果有拒绝的图片举证，可以提供 最多上传4张图片,
+   *      传入调用“商户上传反馈图片”接口返回的media_id，最多上传4张图片凭证
+   *
+   * </pre>
+   */
+  @SerializedName("reject_media_list")
+  private List<String> rejectMediaList;
+
+  /**
+   * <pre>
+   * 字段名：备注
+   * 是否必填：否 string(200)
+   * 描述：任何需要向微信支付客服反馈的信息
+   * </pre>
+   */
+  @SerializedName("remark")
+  private String remark;
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/VerifyCertificateRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/VerifyCertificateRequest.java
index 767a4ce8d8..b589cb2277 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/VerifyCertificateRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/VerifyCertificateRequest.java
@@ -1,6 +1,5 @@
 package com.github.binarywang.wxpay.bean.customs;
 
-import com.github.binarywang.wxpay.v3.SpecEncrypt;
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/FundBillResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/FundBillResult.java
index 206cd1218b..077c2c2336 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/FundBillResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/FundBillResult.java
@@ -48,7 +48,9 @@ public class FundBillResult implements Serializable {
   private FundBill[] downloadBillList;
 
   @Data
-  public static class FundBill {
+  public static class FundBill implements Serializable {
+
+    private static final long serialVersionUID = 4008480977464421822L;
 
     /**
      * <pre>
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/RefundNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/RefundNotifyResult.java
index 89ef5d0cbd..c8c6c10589 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/RefundNotifyResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/RefundNotifyResult.java
@@ -170,6 +170,25 @@ public class RefundNotifyResult implements Serializable {
   @SerializedName(value = "amount")
   private Amount amount;
 
+  /**
+   * <pre>
+   * 字段名：退款出资商户
+   * 变量名：refund_account
+   * 是否必填：否
+   * 类型：string（32）
+   * 描述：
+   *   电商平台垫资退款专用参数。需先确认已开通此功能后，才能使用。若需要开通，请联系微信支付客服。
+   *   枚举值：
+   *   REFUND_SOURCE_PARTNER_ADVANCE : 电商平台垫付，需要向微信支付申请开通
+   *   REFUND_SOURCE_SUB_MERCHANT : 二级商户，默认值
+   *   注意：
+   *   若传入REFUND_SOURCE_PARTNER_ADVANCE，仅代表可以使用垫付退款，实际出款账户需以退款申请受理结果或查单结果为准。
+   *   示例值：REFUND_SOURCE_SUB_MERCHANT
+   * </pre>
+   */
+  @SerializedName(value = "refund_account")
+  private String refundAccount;
+
   @Data
   @NoArgsConstructor
   public static class Amount implements Serializable {
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/RefundQueryResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/RefundQueryResult.java
index bbb30ea897..bfcd499e21 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/RefundQueryResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/RefundQueryResult.java
@@ -183,6 +183,44 @@ public class RefundQueryResult implements Serializable {
    */
   public List<PromotionDetail> promotionDetails;
 
+
+  /**
+   * <pre>
+   * 字段名：退款出资商户
+   * 变量名：refund_account
+   * 是否必填：否
+   * 类型：string（32）
+   * 描述：
+   *   电商平台垫资退款专用参数。需先确认已开通此功能后，才能使用。若需要开通，请联系微信支付客服。
+   *   枚举值：
+   *   REFUND_SOURCE_PARTNER_ADVANCE : 电商平台垫付，需要向微信支付申请开通
+   *   REFUND_SOURCE_SUB_MERCHANT : 二级商户，默认值
+   *   注意：
+   *   若传入REFUND_SOURCE_PARTNER_ADVANCE，仅代表可以使用垫付退款，实际出款账户需以退款申请受理结果或查单结果为准。
+   *   示例值：REFUND_SOURCE_SUB_MERCHANT
+   * </pre>
+   */
+  @SerializedName(value = "refund_account")
+  private String refundAccount;
+
+  /**
+   * <pre>
+   * 字段名：资金账户
+   * 变量名：funds_account
+   * 是否必填：否
+   * 类型：string（32）
+   * 描述：
+   *   若订单处于待分账状态，且未指定垫资退款（即refund_account未指定为REFUND_SOURCE_PARTNER_ADVANCE），
+   *   可以传入此参数，指定退款资金来源账户。当该字段不存在时，默认使用订单交易资金所在账户出款，
+   *   即待分账时使用不可用余额的资金进行退款，已分账或无分账时使用可用余额的资金进行退款。 AVAILABLE：可用余额
+   * 示例值：AVAILABLE
+   * </pre>
+   */
+  @SerializedName(value = "funds_account")
+  private String fundsAccount;
+
+
+
   @Data
   @NoArgsConstructor
   public static class Amount implements Serializable {
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/RefundsRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/RefundsRequest.java
index 96e6c22fab..b453a994f1 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/RefundsRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/RefundsRequest.java
@@ -147,6 +147,41 @@ public class RefundsRequest implements Serializable {
   @SerializedName(value = "notify_url")
   private String notifyUrl;
 
+  /**
+   * <pre>
+   * 字段名：退款出资商户
+   * 变量名：refund_account
+   * 是否必填：否
+   * 类型：string（32）
+   * 描述：
+   *   电商平台垫资退款专用参数。需先确认已开通此功能后，才能使用。若需要开通，请联系微信支付客服。
+   *   枚举值：
+   *   REFUND_SOURCE_PARTNER_ADVANCE : 电商平台垫付，需要向微信支付申请开通
+   *   REFUND_SOURCE_SUB_MERCHANT : 二级商户，默认值
+   *   注意：
+   *   若传入REFUND_SOURCE_PARTNER_ADVANCE，仅代表可以使用垫付退款，实际出款账户需以退款申请受理结果或查单结果为准。
+   *   示例值：REFUND_SOURCE_SUB_MERCHANT
+   * </pre>
+   */
+  @SerializedName(value = "refund_account")
+  private String refundAccount;
+
+  /**
+   * <pre>
+   * 字段名：资金账户
+   * 变量名：funds_account
+   * 是否必填：否
+   * 类型：string（32）
+   * 描述：
+   *   若订单处于待分账状态，且未指定垫资退款（即refund_account未指定为REFUND_SOURCE_PARTNER_ADVANCE），
+   *   可以传入此参数，指定退款资金来源账户。当该字段不存在时，默认使用订单交易资金所在账户出款，
+   *   即待分账时使用不可用余额的资金进行退款，已分账或无分账时使用可用余额的资金进行退款。 AVAILABLE：可用余额
+   * 示例值：AVAILABLE
+   * </pre>
+   */
+  @SerializedName(value = "funds_account")
+  private String fundsAccount;
+
   @Data
   @Builder
   @NoArgsConstructor(access = AccessLevel.PRIVATE)
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/RefundsResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/RefundsResult.java
index 9637587409..bbd3eabb2d 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/RefundsResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/RefundsResult.java
@@ -10,7 +10,6 @@
 import lombok.NoArgsConstructor;
 
 import java.io.Serializable;
-import java.util.Date;
 
 /**
  * 退款结果
@@ -240,4 +239,22 @@ public static class PromotionDetail implements Serializable {
 
   }
 
+
+  /**
+   * <pre>
+   * 字段名：退款资金来源
+   * 变量名：refund_account
+   * 是否必填：否
+   * 类型：string（32）
+   * 描述：
+   *   枚举值：
+   * REFUND_SOURCE_PARTNER_ADVANCE : 电商平台垫付
+   * REFUND_SOURCE_SUB_MERCHANT : 二级商户，默认值
+   * 示例值：REFUND_SOURCE_SUB_MERCHANT
+   * </pre>
+   */
+  @SerializedName(value = "refund_account")
+  private String refundAccount;
+
+
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/ReturnAdvanceResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/ReturnAdvanceResult.java
new file mode 100644
index 0000000000..442f0f15b0
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/ReturnAdvanceResult.java
@@ -0,0 +1,158 @@
+package com.github.binarywang.wxpay.bean.ecommerce;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+
+/**
+ * 垫付退款回补API结果
+ * * <pre>
+ *  *   文档地址：https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_6_4.shtml
+ *  * </pre>
+ *
+ * @author yantao
+ * created on  2024/11/20
+ */
+@Data
+@NoArgsConstructor
+public class ReturnAdvanceResult implements Serializable {
+
+  private static final long serialVersionUID = -186851559004865784L;
+
+  /**
+   * <pre>
+   * 字段名：微信退款单号
+   * 变量名：refund_id
+   * 是否必填：是
+   * 类型：string（32）
+   * 描述：
+   * 微信支付退款单的主键，唯一定义此资源的标识。 必须是垫付退款的微信支付退款单
+   * 示例值：50000000382019052709732678859
+   * </pre>
+   */
+  @SerializedName(value = "refund_id")
+  private String refundId;
+
+  /**
+   * <pre>
+   * 字段名：微信回补单号
+   * 变量名：advance_return_id
+   * 是否必填：是
+   * 类型：string（32）
+   * 描述：微信支付生成的垫付回补操作单号
+   * 示例值：1215562501201407033233368018
+   * </pre>
+   */
+  @SerializedName(value = "advance_return_id")
+  private String advanceReturnId	;
+
+  /**
+   * <pre>
+   * 字段名：垫付回补金额
+   * 变量名：return_amount
+   * 是否必填：是
+   * 类型：int
+   * 描述：退款单对应的垫付退款的金额
+   * 示例值：888
+   * </pre>
+   */
+  @SerializedName(value = "return_amount")
+  private Integer returnAmount	;
+
+  /**
+   * <pre>
+   * 字段名：出款方商户号
+   * 变量名：payer_mchid
+   * 是否必填：是
+   * 类型：string（32）
+   * 描述：微信支付分配给出款方的商户号
+   * 示例值：1900000109
+   * </pre>
+   */
+  @SerializedName(value = "payer_mchid")
+  private String  payerMchid ;
+
+  /**
+   * <pre>
+   * 字段名：出款方账户
+   * 变量名：payer_account
+   * 是否必填：是
+   * 类型：string（32）
+   * 描述：
+   * 枚举值：
+   * BASIC：基本账户
+   * OPERATION：运营账户
+   * 示例值：BASIC
+   * </pre>
+   */
+  @SerializedName(value = "payer_account")
+  private String payerAccount;
+
+  /**
+   * <pre>
+   * 字段名：入账方商户号
+   * 变量名：payee_mchid
+   * 是否必填：是
+   * 类型：string（32）
+   * 描述：
+   * 微信支付分配给入账方的商户号
+   * 示例值：1900000108
+   * </pre>
+   */
+  @SerializedName(value = "payee_mchid")
+  private String payeeMchid;
+
+  /**
+   * <pre>
+   * 字段名：入账方账户
+   * 变量名：payee_account
+   * 是否必填：是
+   * 类型：string（32）
+   * 描述：枚举值：
+   * BASIC：基本账户
+   * OPERATION：运营账户
+   * 示例值：BASIC
+   * </pre>
+   */
+  @SerializedName(value = "payee_account")
+  private String payeeAccount;
+
+  /**
+   * <pre>
+   * 字段名：垫付回补结果
+   * 变量名：result
+   * 是否必填：是
+   * 类型：string（32）
+   * 描述：枚举值：
+   * SUCCESS：回补成功
+   * FAILED：回补失败，出款方账户余额不足时发生
+   * PROCESSING：处理中
+   * 示例值：SUCCESS
+   * </pre>
+   */
+  @SerializedName(value = "result")
+  private String result	;
+
+  /**
+   * <pre>
+   * 字段名：垫付回补完成时间
+   * 变量名：success_time
+   * 是否必填：否
+   * 类型：string（64）
+   * 描述：垫付回补完成的时间，遵循rfc3339标准格式，
+   * 格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE，yyyy-MM-DD表示年月日，
+   * T出现在字符串中，表示time元素的开头，HH:mm:ss表示时分秒，
+   * TIMEZONE表示时区（+08:00表示东八区时间，领先UTC 8小时，即北京时间）。
+   * 例如：2015-05-20T13:29:35+08:00表示北京时间2015年05月20日13点29分35秒。
+   * 示例值：2018-06-08T10:34:56+08:00
+   * </pre>
+   */
+  @SerializedName(value = "success_time")
+  private String successTime;
+
+
+
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/ReturnOrdersRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/ReturnOrdersRequest.java
index e3e7c98e34..b1661209a6 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/ReturnOrdersRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/ReturnOrdersRequest.java
@@ -118,4 +118,18 @@ public class ReturnOrdersRequest implements Serializable {
    */
   @SerializedName(value = "description")
   private String description;
+
+  /**
+   * <pre>
+   * 字段名：微信订单号
+   * 变量名：transaction_id
+   * 是否必填：否
+   * 类型：string（32）
+   * 描述：
+   *  微信支付订单号，大于6个月的订单，必填
+   *  示例值：4208450740201411110007820472
+   * </pre>
+   */
+  @SerializedName(value = "transaction_id")
+  private String transactionId;
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/ReturnOrdersResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/ReturnOrdersResult.java
index b136844f86..0b0d093e3c 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/ReturnOrdersResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/ecommerce/ReturnOrdersResult.java
@@ -4,7 +4,6 @@
 import lombok.*;
 
 import java.io.Serializable;
-import java.util.Date;
 
 
 /**
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponCodeRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponCodeRequest.java
index fa6ca553e9..2ab481849e 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponCodeRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponCodeRequest.java
@@ -18,7 +18,7 @@
 @Data
 @NoArgsConstructor
 public class BusiFavorCouponCodeRequest implements Serializable {
-  public static final float serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
 
   /**
    * <pre>* 字段名：批次号
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponCodeResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponCodeResult.java
index ca45a091c4..bca9ea932e 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponCodeResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponCodeResult.java
@@ -18,7 +18,7 @@
 @Data
 @NoArgsConstructor
 public class BusiFavorCouponCodeResult implements Serializable {
-  public static final float serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
 
   /**
    * <pre>* 字段名：批次号
@@ -130,8 +130,8 @@ public class BusiFavorCouponCodeResult implements Serializable {
 
   @Data
   @NoArgsConstructor
-  public static class FailCode {
-    public static final float serialVersionUID = 1L;
+  public static class FailCode implements Serializable {
+    private static final long serialVersionUID = 1L;
 
     /**
      * <pre>* 字段名：上传失败的券code
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponsUrlRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponsUrlRequest.java
index 11319e56b4..8af44901e0 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponsUrlRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponsUrlRequest.java
@@ -4,6 +4,8 @@
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import java.io.Serializable;
+
 /**
  * H5发券请求对象
  * <pre>
@@ -14,8 +16,8 @@
  */
 @Data
 @NoArgsConstructor
-public class BusiFavorCouponsUrlRequest {
-  public static final float serialVersionUID = 1L;
+public class BusiFavorCouponsUrlRequest implements Serializable {
+  private static final long serialVersionUID = 1L;
 
   /**
    * <pre>
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponsUseRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponsUseRequest.java
index ab8a8ba2a5..9d365054e9 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponsUseRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorCouponsUseRequest.java
@@ -4,6 +4,8 @@
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import java.io.Serializable;
+
 /**
  * 核销用户券请求对象
  * <pre>
@@ -14,8 +16,8 @@
  */
 @Data
 @NoArgsConstructor
-public class BusiFavorCouponsUseRequest {
-  public static final float serialVersionUID = 1L;
+public class BusiFavorCouponsUseRequest implements Serializable {
+  private static final long serialVersionUID = 1L;
 
   /**
    * <pre>
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryOneUserCouponsRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryOneUserCouponsRequest.java
index 3dad3fe5d1..0a53cd33d1 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryOneUserCouponsRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryOneUserCouponsRequest.java
@@ -17,7 +17,7 @@
 @Data
 @NoArgsConstructor
 public class BusiFavorQueryOneUserCouponsRequest implements Serializable {
-  public static final float serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
 
   /**
    * <pre>* 字段名：用户标识
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryOneUserCouponsResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryOneUserCouponsResult.java
index 6db7d303a9..566957eb51 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryOneUserCouponsResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryOneUserCouponsResult.java
@@ -20,7 +20,7 @@
 @Data
 @NoArgsConstructor
 public class BusiFavorQueryOneUserCouponsResult implements Serializable {
-  public static final float serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
 
   /**
    * <pre>* 字段名：批次归属商户号
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryUserCouponsRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryUserCouponsRequest.java
index 600a48c8de..0c417c425a 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryUserCouponsRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryUserCouponsRequest.java
@@ -17,7 +17,7 @@
 @Data
 @NoArgsConstructor
 public class BusiFavorQueryUserCouponsRequest implements Serializable {
-  public static final float serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
 
   /**
    * <pre>* 字段名：用户标识
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryUserCouponsResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryUserCouponsResult.java
index 9b5f57b040..c2906be27e 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryUserCouponsResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/BusiFavorQueryUserCouponsResult.java
@@ -18,7 +18,7 @@
 @Data
 @NoArgsConstructor
 public class BusiFavorQueryUserCouponsResult implements Serializable {
-  public static final float serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
 
   /**
    * <pre>* 字段名：+结果集
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsGetResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsGetResult.java
index f8f342de1c..6f1824f646 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsGetResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorCouponsGetResult.java
@@ -1,5 +1,6 @@
 package com.github.binarywang.wxpay.bean.marketing;
 
+import com.github.binarywang.wxpay.bean.result.BaseWxPayV3Result;
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
 import lombok.NoArgsConstructor;
@@ -13,7 +14,7 @@
  */
 @NoArgsConstructor
 @Data
-public class FavorCouponsGetResult implements Serializable {
+public class FavorCouponsGetResult extends BaseWxPayV3Result {
 
   private static final long serialVersionUID = 1L;
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksCreateRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksCreateRequest.java
index 855edc8528..375dd308d8 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksCreateRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksCreateRequest.java
@@ -1,6 +1,7 @@
 package com.github.binarywang.wxpay.bean.marketing;
 
 import com.github.binarywang.wxpay.bean.marketing.enums.BackgroundColorEnum;
+import com.github.binarywang.wxpay.bean.marketing.enums.JumpTargetEnum;
 import com.github.binarywang.wxpay.bean.marketing.enums.StockTypeEnum;
 import com.github.binarywang.wxpay.bean.marketing.enums.TradeTypeEnum;
 import com.google.gson.annotations.SerializedName;
@@ -392,6 +393,24 @@ public static class PatternInfo implements Serializable {
      */
     @SerializedName(value = "coupon_image")
     private String couponImage;
+
+    /**
+     * 卡包跳转目标
+     */
+    @SerializedName("jump_target")
+    private JumpTargetEnum jumpTarget;
+
+    /**
+     * 小程序appid
+     */
+    @SerializedName("mini_program_appid")
+    private String miniProgramAppid;
+
+    /**
+     * 小程序path
+     */
+    @SerializedName("mini_program_path")
+    private String miniProgramPath;
   }
 
   @Data
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksCreateResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksCreateResult.java
index 74ac6fd205..381056b5a9 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksCreateResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksCreateResult.java
@@ -1,5 +1,6 @@
 package com.github.binarywang.wxpay.bean.marketing;
 
+import com.github.binarywang.wxpay.bean.result.BaseWxPayV3Result;
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
 import lombok.NoArgsConstructor;
@@ -13,7 +14,7 @@
  */
 @NoArgsConstructor
 @Data
-public class FavorStocksCreateResult implements Serializable {
+public class FavorStocksCreateResult extends BaseWxPayV3Result {
 
   private static final long serialVersionUID = 1L;
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksGetResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksGetResult.java
index 294f273def..591afa7e51 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksGetResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksGetResult.java
@@ -1,5 +1,6 @@
 package com.github.binarywang.wxpay.bean.marketing;
 
+import com.github.binarywang.wxpay.bean.result.BaseWxPayV3Result;
 import com.google.gson.annotations.SerializedName;
 import lombok.Data;
 import lombok.NoArgsConstructor;
@@ -14,7 +15,7 @@
  */
 @NoArgsConstructor
 @Data
-public class FavorStocksGetResult implements Serializable {
+public class FavorStocksGetResult extends BaseWxPayV3Result {
 
   private static final long serialVersionUID = 1L;
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/AvailableWeek.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/AvailableWeek.java
index 2718b32770..487291a739 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/AvailableWeek.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/AvailableWeek.java
@@ -17,7 +17,7 @@
 @Data
 @NoArgsConstructor
 public class AvailableWeek implements Serializable {
-  public static final float serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
 
   /**
    * <pre>
@@ -46,12 +46,12 @@ public class AvailableWeek implements Serializable {
    * </pre>
    */
   @SerializedName(value = "available_day_time")
-  private AvailableDayTime availableDayTime;
+  private AvailableDayTimeItem[] availableDayTime;
 
   @Data
   @NoArgsConstructor
-  public static class AvailableDayTime implements Serializable {
-    public static final float serialVersionUID = 1L;
+  public static class AvailableDayTimeItem implements Serializable {
+    private static final long serialVersionUID = 1L;
 
     /**
      * <pre>
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/CouponAvailableTime.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/CouponAvailableTime.java
index 31833c1188..f41692c068 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/CouponAvailableTime.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/CouponAvailableTime.java
@@ -18,7 +18,7 @@
 @Data
 @NoArgsConstructor
 public class CouponAvailableTime implements Serializable {
-  public static final float serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
 
   /**
    * <pre>
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/IrregularyAvaliableTime.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/IrregularyAvaliableTime.java
index 4ddd196e56..0b11010493 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/IrregularyAvaliableTime.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/busifavor/IrregularyAvaliableTime.java
@@ -18,7 +18,7 @@
 @NoArgsConstructor
 public class IrregularyAvaliableTime implements Serializable {
 
-  public static final float serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
 
   /**
    * <pre>
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/BackgroundColorEnum.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/BackgroundColorEnum.java
index d9ba753346..b37765f8f2 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/BackgroundColorEnum.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/BackgroundColorEnum.java
@@ -52,6 +52,16 @@ public enum BackgroundColorEnum {
    */
   COLOR080("COLOR080", "#EE903C"),
 
+  /**
+   * 颜色 #F08500
+   */
+  COLOR081("COLOR081", "#F08500"),
+
+  /**
+   * 颜色 #A9D92D
+   */
+  COLOR082("COLOR082", "#A9D92D"),
+
   /**
    * 颜色 #DD6549
    */
@@ -61,8 +71,17 @@ public enum BackgroundColorEnum {
    * 颜色 #CC463D
    */
   COLOR100("COLOR100", "#CC463D"),
-  ;
 
+  /**
+   * 颜色 #CF3E36
+   */
+  COLOR101("COLOR101", "#CF3E36"),
+
+  /**
+   * 颜色 #5E6671
+   */
+  COLOR102("COLOR102", "#5E6671"),
+  ;
   /**
    * 色值
    */
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/JumpTargetEnum.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/JumpTargetEnum.java
new file mode 100644
index 0000000000..dce0b34556
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/enums/JumpTargetEnum.java
@@ -0,0 +1,34 @@
+package com.github.binarywang.wxpay.bean.marketing.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 卡包跳转目标
+ *
+ * @author wangerwei
+ */
+@Getter
+@AllArgsConstructor
+public enum JumpTargetEnum {
+
+  /**
+   * PAYMENT_CODE：点击“立即使用”跳转至微信支付付款码
+   */
+  PAYMENT_CODE("PAYMENT_CODE"),
+
+  /**
+   * MINI_PROGRAM：点击“立即使用”跳转至配置的商家小程序（需要指定小程序appid和path）
+   */
+  MINI_PROGRAM("MINI_PROGRAM"),
+
+  /**
+   * DEFAULT_PAGE：点击“立即使用”跳转至默认页面
+   */
+  DEFAULT_PAGE("DEFAULT_PAGE");
+
+  /**
+   * 批次类型
+   */
+  private final String value;
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchDetailsRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchDetailsRequest.java
index 9aa51ce742..bbb4e93ab4 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchDetailsRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchDetailsRequest.java
@@ -23,7 +23,7 @@
 @Data
 @NoArgsConstructor
 public class BatchDetailsRequest implements Serializable {
-  public static final float serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
   /**
    * <pre>
    * 字段名：微信支付批次单号
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchDetailsResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchDetailsResult.java
index 437def08f2..4ca7958ed5 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchDetailsResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchDetailsResult.java
@@ -7,7 +7,6 @@
 import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 
 import java.io.Serializable;
-import java.util.Date;
 
 /**
  * <pre>
@@ -26,7 +25,7 @@
 @Data
 @NoArgsConstructor
 public class BatchDetailsResult implements Serializable {
-  public static final float serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
 
   @Override
   public String toString() {
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchNumberRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchNumberRequest.java
index 9f53843d66..127c38cdc6 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchNumberRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchNumberRequest.java
@@ -18,7 +18,7 @@
 @Data
 @NoArgsConstructor
 public class BatchNumberRequest implements Serializable {
-  public static final float serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
 
   /**
    * <pre>
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchNumberResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchNumberResult.java
index 1defcca943..a59ccbc85f 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchNumberResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BatchNumberResult.java
@@ -20,7 +20,7 @@
 @Data
 @NoArgsConstructor
 public class BatchNumberResult implements Serializable {
-  public static final float serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
 
   @Override
   public String toString() {
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BillReceiptResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BillReceiptResult.java
index ea83328308..fc0b97d7bb 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BillReceiptResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/BillReceiptResult.java
@@ -20,7 +20,7 @@
 @Data
 @NoArgsConstructor
 public class BillReceiptResult implements Serializable {
-  public static final float serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
 
   @Override
   public String toString() {
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/DownloadRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/DownloadRequest.java
index 50ca1feac7..3f147abd00 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/DownloadRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/DownloadRequest.java
@@ -21,7 +21,7 @@
 @Data
 @NoArgsConstructor
 public class DownloadRequest implements Serializable {
-  public static final float serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
 
   /**
    * <pre>
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ElectronicReceiptsRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ElectronicReceiptsRequest.java
index 1f4d8134f4..cc419d3a4f 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ElectronicReceiptsRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ElectronicReceiptsRequest.java
@@ -20,7 +20,7 @@
 @Data
 @NoArgsConstructor
 public class ElectronicReceiptsRequest implements Serializable {
-  public static final float serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
   /**
    * <pre>
    * 字段名：受理类型
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ElectronicReceiptsResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ElectronicReceiptsResult.java
index 114b1982c3..4e0581108c 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ElectronicReceiptsResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ElectronicReceiptsResult.java
@@ -20,7 +20,7 @@
 @Data
 @NoArgsConstructor
 public class ElectronicReceiptsResult implements Serializable {
-  public static final float serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
   /**
    * <pre>
    * 字段名：受理类型
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/MerchantBatchRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/MerchantBatchRequest.java
index fe6450b22e..a319d3f4b3 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/MerchantBatchRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/MerchantBatchRequest.java
@@ -20,7 +20,7 @@
 @Data
 @NoArgsConstructor
 public class MerchantBatchRequest implements Serializable {
-  public static final float serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
   /**
    * <pre>
    * 字段名：商家批次单号
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/PartnerTransferRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/PartnerTransferRequest.java
index bd06b5db4b..0e8418cca9 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/PartnerTransferRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/PartnerTransferRequest.java
@@ -19,7 +19,7 @@
 @Data
 @NoArgsConstructor
 public class PartnerTransferRequest implements Serializable {
-  public static final float serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
 
   /**
    * <pre>
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/PartnerTransferResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/PartnerTransferResult.java
index cca369b408..d9c8019462 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/PartnerTransferResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/PartnerTransferResult.java
@@ -18,7 +18,7 @@
 @Data
 @NoArgsConstructor
 public class PartnerTransferResult implements Serializable {
-  public static final float serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
   /**
    * <pre>
    * 字段名：商家批次单号
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ReceiptBillRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ReceiptBillRequest.java
index deda24d426..1995ac1656 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ReceiptBillRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/marketing/transfer/ReceiptBillRequest.java
@@ -18,7 +18,7 @@
 @Data
 @NoArgsConstructor
 public class ReceiptBillRequest implements Serializable {
-  public static final float serialVersionUID = 1L;
+  private static final long serialVersionUID = 1L;
   /**
    * <pre>
    * 字段名：商家批次单号
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/ComplaintNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/ComplaintNotifyResult.java
index a5d18df6df..9464144c1d 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/ComplaintNotifyResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/ComplaintNotifyResult.java
@@ -47,13 +47,23 @@ public static class DecryptNotifyResult implements Serializable {
      * 是否必填：是
      * 描述：
      * 触发本次投诉通知回调的具体动作类型，枚举如下：
+     * 常规通知：
      * CREATE_COMPLAINT：用户提交投诉
      * CONTINUE_COMPLAINT：用户继续投诉
      * USER_RESPONSE：用户新留言
      * RESPONSE_BY_PLATFORM：平台新留言
-     * SELLER_REFUND：收款方全额退款
+     * SELLER_REFUND：商户发起全额退款
      * MERCHANT_RESPONSE：商户新回复
      * MERCHANT_CONFIRM_COMPLETE：商户反馈处理完成
+     * USER_APPLY_PLATFORM_SERVICE：用户申请平台协助
+     * USER_CANCEL_PLATFORM_SERVICE：用户取消平台协助
+     * PLATFORM_SERVICE_FINISHED：客服结束平台协助
+     *
+     * 申请退款单的附加通知：
+     * 以下通知会更新投诉单状态，建议收到后查询投诉单详情。
+     * MERCHANT_APPROVE_REFUND：商户同意退款
+     * MERCHANT_REJECT_REFUND：商户驳回退款
+     * REFUND_SUCCESS：退款到账
      * </pre>
      */
     @SerializedName(value = "action_type")
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResult.java
index bd9a6f3ecf..27e8c1e1ec 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayOrderNotifyResult.java
@@ -387,7 +387,7 @@ protected void composeCoupons() {
     if (this.couponCount == null || this.couponCount == 0) {
       return;
     }
-    this.couponList = new ArrayList(couponCount);
+    this.couponList = new ArrayList<>(couponCount);
     for (int i = 0; i < this.couponCount; i++) {
       WxPayOrderNotifyCoupon coupon = new WxPayOrderNotifyCoupon();
       coupon.setCouponId(this.getXmlValue("xml/coupon_id_" + i));
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java
index ae86b8c854..8615a2e461 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java
@@ -273,7 +273,7 @@ public String toString() {
      * </pre>
      */
     @XStreamAlias("refund_recv_accout")
-    private String refundRecvAccout;
+    private String refundRecvAccount;
 
     /**
      * <pre>
@@ -324,7 +324,7 @@ public void loadXML(Document d) {
       settlementRefundFee = readXmlInteger(d, "settlement_refund_fee");
       refundStatus = readXmlString(d, "refund_status");
       successTime = readXmlString(d, "success_time");
-      refundRecvAccout = readXmlString(d, "refund_recv_accout");
+      refundRecvAccount = readXmlString(d, "refund_recv_accout");
       refundAccount = readXmlString(d, "refund_account");
       refundRequestSource = readXmlString(d, "refund_request_source");
     }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/Device.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/Device.java
new file mode 100644
index 0000000000..3060b0ff47
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/Device.java
@@ -0,0 +1,38 @@
+package com.github.binarywang.wxpay.bean.payscore;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 设备信息
+ **/
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class Device  implements Serializable {
+
+  private static final long serialVersionUID = -4510224826631515321L;
+
+
+  /**
+   * 服务开始的设备ID
+   */
+  @SerializedName("start_device_id")
+  private String startDeviceId;
+
+  /**
+   * 服务结束的设备ID
+   */
+  @SerializedName("end_device_id")
+  private String endDeviceId;
+
+  /**
+   * 物料编码
+   */
+  @SerializedName("materiel_no")
+  private String materielNo;
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/WxPartnerUserAuthorizationStatusNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/WxPartnerUserAuthorizationStatusNotifyResult.java
index feeabaac16..be44427dfc 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/WxPartnerUserAuthorizationStatusNotifyResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/WxPartnerUserAuthorizationStatusNotifyResult.java
@@ -4,7 +4,6 @@
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.NoArgsConstructor;
-import me.chanjar.weixin.common.util.json.WxGsonBuilder;
 
 import java.io.Serializable;
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/WxPayScoreRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/WxPayScoreRequest.java
index 3c58a62e80..020ed05cb7 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/WxPayScoreRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/payscore/WxPayScoreRequest.java
@@ -42,6 +42,7 @@ public String toJson() {
    * openid : oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
    * need_user_confirm : true
    * profitSharing : false：不分账，默认：false,true：分账
+   * device : {"start_device_id":"202501","end_device_id":"202502","materiel_no":"212323232"}
    */
   @SerializedName("out_order_no")
   private String outOrderNo;
@@ -95,4 +96,6 @@ public String toJson() {
    */
   @SerializedName("complete_time")
   private String completeTime;
+  @SerializedName("device")
+  private Device device;
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/ReceiverList.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/ReceiverList.java
index d3d8c07d37..505d7e28d4 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/ReceiverList.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/ReceiverList.java
@@ -12,7 +12,7 @@
 
 public class ReceiverList implements Serializable {
   private static final long serialVersionUID = -1316860887694489921L;
-  ArrayList list;
+  ArrayList<Receiver> list;
 
   private ReceiverList() {
   }
@@ -23,7 +23,7 @@ private ReceiverList() {
    */
   public static ReceiverList getInstance() {
     ReceiverList receiverList = new ReceiverList();
-    receiverList.list = new ArrayList();
+    receiverList.list = new ArrayList<>();
     return receiverList;
   }
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/request/ProfitSharingReceiverV3Request.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/request/ProfitSharingReceiverV3Request.java
index b8de4f5d5b..98e99b3e2c 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/request/ProfitSharingReceiverV3Request.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/request/ProfitSharingReceiverV3Request.java
@@ -1,16 +1,10 @@
 package com.github.binarywang.wxpay.bean.profitsharing.request;
 
-import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
-import com.github.binarywang.wxpay.constant.WxPayConstants;
-import com.github.binarywang.wxpay.exception.WxPayException;
 import com.github.binarywang.wxpay.v3.SpecEncrypt;
 import com.google.gson.annotations.SerializedName;
-import com.thoughtworks.xstream.annotations.XStreamAlias;
 import lombok.*;
-import me.chanjar.weixin.common.annotation.Required;
 
 import java.io.Serializable;
-import java.util.Map;
 
 /**
  * 添加/删除分账接受方请求对象
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/request/ProfitSharingRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/request/ProfitSharingRequest.java
index 95b5e67fc9..1cc72b1fa8 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/request/ProfitSharingRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/request/ProfitSharingRequest.java
@@ -3,14 +3,10 @@
 import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
 import com.github.binarywang.wxpay.constant.WxPayConstants;
 import com.github.binarywang.wxpay.exception.WxPayException;
-import com.github.binarywang.wxpay.v3.SpecEncrypt;
-import com.google.gson.Gson;
-import com.google.gson.annotations.SerializedName;
 import com.thoughtworks.xstream.annotations.XStreamAlias;
 import lombok.*;
 import me.chanjar.weixin.common.annotation.Required;
 
-import java.io.Serializable;
 import java.util.Map;
 
 /**
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/result/ProfitSharingQueryResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/result/ProfitSharingQueryResult.java
index 437a82e18f..6c222ddc54 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/result/ProfitSharingQueryResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/result/ProfitSharingQueryResult.java
@@ -92,7 +92,7 @@ protected void loadXml(Document d) {
   }
 
   @Data
-  public class Receiver {
+  public static class Receiver {
     /**
      * 分账接收方类型
      */
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/result/ProfitSharingReceiverV3Result.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/result/ProfitSharingReceiverV3Result.java
index 996bb5e789..141a2df94b 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/result/ProfitSharingReceiverV3Result.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/profitsharing/result/ProfitSharingReceiverV3Result.java
@@ -1,13 +1,8 @@
 package com.github.binarywang.wxpay.bean.profitsharing.result;
 
-import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
 import com.github.binarywang.wxpay.v3.SpecEncrypt;
 import com.google.gson.annotations.SerializedName;
-import com.thoughtworks.xstream.annotations.XStreamAlias;
 import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.NoArgsConstructor;
-import org.w3c.dom.Document;
 
 import java.io.Serializable;
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java
index 5eeeb36604..526a961e47 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/BaseWxPayRequest.java
@@ -20,9 +20,9 @@
 
 import java.io.Serializable;
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Optional;
 
 import static com.github.binarywang.wxpay.constant.WxPayConstants.SignType.ALL_SIGN_TYPES;
 
@@ -147,21 +147,21 @@ public void setWorkWxSign(String workWxSign) {
    * @return the integer
    */
   public static Integer yuanToFen(String yuan) {
-    return new BigDecimal(yuan).setScale(2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).intValue();
+    return new BigDecimal(yuan).setScale(2, RoundingMode.HALF_UP).multiply(new BigDecimal(100)).intValue();
   }
 
   /**
    * 元转分
    */
   public static Integer yuan2Fen(BigDecimal yuan) {
-    return yuan.multiply(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_HALF_UP).intValue();
+    return yuan.multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP).intValue();
   }
 
   /**
    * 分转元
    */
   public static BigDecimal fen2Yuan(BigDecimal fen) {
-    return fen.divide(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
+    return fen.divide(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP);
   }
 
   /**
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/CombineCloseRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/CombineCloseRequest.java
index b397f0f1c0..428878dc77 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/CombineCloseRequest.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/CombineCloseRequest.java
@@ -87,5 +87,33 @@ public static class SubOrders implements Serializable {
      */
     @SerializedName(value = "out_trade_no")
     private String outTradeNo;
+    /**
+     * <pre>
+     * 字段名：二级商户号
+     * 变量名：sub_mchid
+     * 是否必填：是
+     * 类型：string[1,32]
+     * 描述：
+     *  二级商户商户号，由微信支付生成并下发。服务商子商户的商户号，被合单方。直连商户不用传二级商户号。
+     *  示例值：1900000109
+     * </pre>
+     */
+    @SerializedName(value = "sub_mchid")
+    private String subMchid;
+    /**
+     * <pre>
+     * 字段名：子商户应用ID
+     * 变量名：sub_appid
+     * 是否必填：是
+     * 类型：string[1,32]
+     * 描述：
+     *  子商户申请的应用ID，全局唯一。请求基础下单接口时请注意APPID的应用属性，例如公众号场景下，
+     *  需使用应用属性为公众号的APPID 若sub_openid有传的情况下，
+     *  sub_appid必填，且sub_appid需与sub_openid对应
+     *  示例值：wxd678efh567hg6999
+     * </pre>
+     */
+    @SerializedName(value = "sub_appid")
+    private String subAppid;
   }
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayPartnerRefundV3Request.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayPartnerRefundV3Request.java
index c522c90d88..8f3e8ebd10 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayPartnerRefundV3Request.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayPartnerRefundV3Request.java
@@ -6,7 +6,6 @@
 import lombok.experimental.Accessors;
 
 import java.io.Serializable;
-import java.util.List;
 
 /**
  * 微信支付服务商退款请求
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3Request.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3Request.java
index 98dae388ef..8ac588de81 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3Request.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3Request.java
@@ -250,6 +250,12 @@ public static class Payer implements Serializable {
      */
     @SerializedName(value = "openid")
     private String openid;
+
+    /**
+     * 实名支付用户身份标识
+     */
+    @SerializedName(value = "identity")
+    private Identity identity;
   }
 
   @Data
@@ -572,4 +578,36 @@ public static class SettleInfo implements Serializable {
     @SerializedName(value = "profit_sharing")
     private Boolean profitSharing;
   }
+
+
+  @Data
+  @NoArgsConstructor
+  public static class Identity implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 证件类型
+     * IDCARD:身份证
+     * HONGKONG_MACAO:港澳回乡证
+     * HONGKONG_MACAO_RESIDENT:港澳居住证
+     * TAIWAN_RESIDENT:台湾居住证
+     * FOREIGN_RESIDENT:外国人永居证
+     * OVERSEA_PASSPORT:护照
+     */
+    @SerializedName(value = "type")
+    private String type;
+    /**
+     * 证件号
+     * 证件号，如身份证号。
+     * 示例值：43102119910910512X
+     */
+    @SerializedName(value = "number")
+    private String number;
+    /**
+     * 证件姓名。
+     * 示例值：周星星
+     */
+    @SerializedName(value = "name")
+    private String name;
+  }
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResult.java
index 0c288b5507..109fab66bc 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayResult.java
@@ -194,7 +194,7 @@ private void loadBasicXML(Document d) {
 
   protected static Integer readXmlInteger(Node d, String tagName) {
     String content = readXmlString(d, tagName);
-    if (content == null || content.trim().length() == 0) {
+    if (content == null || content.trim().isEmpty()) {
       return null;
     }
     return Integer.parseInt(content);
@@ -232,7 +232,7 @@ public static String readXmlString(Document d, String tagName) {
 
   protected static Integer readXmlInteger(Document d, String tagName) {
     String content = readXmlString(d, tagName);
-    if (content == null || content.trim().length() == 0) {
+    if (content == null || content.trim().isEmpty()) {
       return null;
     }
 
@@ -241,7 +241,7 @@ protected static Integer readXmlInteger(Document d, String tagName) {
 
   protected static Long readXmlLong(Document d, String tagName) {
     String content = readXmlString(d, tagName);
-    if (content == null || content.trim().length() == 0) {
+    if (content == null || content.trim().isEmpty()) {
       return null;
     }
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayV3Result.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayV3Result.java
new file mode 100644
index 0000000000..88724b939e
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/BaseWxPayV3Result.java
@@ -0,0 +1,42 @@
+package com.github.binarywang.wxpay.bean.result;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * <pre>
+ * 微信支付v3结果共用属性类.
+ * 用于保存原始JSON响应内容，便于访问API返回的新增字段.
+ * </pre>
+ *
+ * @author Binary Wang
+ */
+@Data
+public abstract class BaseWxPayV3Result implements Serializable {
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * 原始JSON字符串.
+   * 保存微信支付v3 API返回的原始JSON内容，便于访问未在Result类中定义的字段.
+   */
+  private String rawJsonString;
+
+  /**
+   * 获取原始JSON响应内容.
+   *
+   * @return 原始JSON字符串
+   */
+  public String getRawJsonString() {
+    return rawJsonString;
+  }
+
+  /**
+   * 设置原始JSON响应内容.
+   *
+   * @param rawJsonString 原始JSON字符串
+   */
+  public void setRawJsonString(String rawJsonString) {
+    this.rawJsonString = rawJsonString;
+  }
+}
\ No newline at end of file
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxWithholdNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxWithholdNotifyResult.java
index 288e8b933f..f2d96804d2 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxWithholdNotifyResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxWithholdNotifyResult.java
@@ -224,7 +224,7 @@ protected void composeCoupons() {
     if (this.couponCount == null || this.couponCount == 0) {
       return;
     }
-    this.couponList = new ArrayList(couponCount);
+    this.couponList = new ArrayList<>(couponCount);
     for (int i = 0; i < this.couponCount; i++) {
       WxPayOrderNotifyCoupon coupon = new WxPayOrderNotifyCoupon();
       coupon.setCouponId(this.getXmlValue("xml/coupon_id_" + i));
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxWithholdOrderQueryResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxWithholdOrderQueryResult.java
index f625462e16..3ce0079f5b 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxWithholdOrderQueryResult.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/WxWithholdOrderQueryResult.java
@@ -147,7 +147,7 @@ protected void composeCoupons() {
     if (this.couponCount == null || this.couponCount == 0) {
       return;
     }
-    this.couponList = new ArrayList(couponCount);
+    this.couponList = new ArrayList<>(couponCount);
     for (int i = 0; i < this.couponCount; i++) {
       WxPayOrderNotifyCoupon coupon = new WxPayOrderNotifyCoupon();
       coupon.setCouponId(this.getXmlValue("xml/coupon_id_" + i));
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsCancelResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsCancelResult.java
new file mode 100644
index 0000000000..9e59fecf73
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsCancelResult.java
@@ -0,0 +1,48 @@
+package com.github.binarywang.wxpay.bean.transfer;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * <pre>
+ * 商家转账到零钱撤销转账接口
+ * 文档地址：https://pay.weixin.qq.com/doc/v3/merchant/4012716458
+ * </pre>
+ *
+ * @author Nor
+ * @date 2025/1/17
+ */
+@Data
+@NoArgsConstructor
+public class TransferBillsCancelResult implements Serializable {
+  private static final long serialVersionUID = -4935840810530008418L;
+
+  /**
+   * 【商户单号】 商户系统内部的商家单号，要求此参数只能由数字、大小写字母组成，在商户系统内部唯一
+   */
+  @SerializedName("out_bill_no")
+  private String outBillNo;
+
+  /**
+   * 【微信转账单号】 微信转账单号，微信商家转账系统返回的唯一标识
+   */
+  @SerializedName("transfer_bill_no")
+  private String transferBillNo;
+
+  /**
+   * 【单据状态】 商家转账订单状态
+   * 可选取值
+   * CANCELING: 商户撤销请求受理成功，该笔转账正在撤销中
+   * CANCELLED: 转账撤销完成
+   */
+  private String state;
+
+  /**
+   * 【最后一次单据状态变更时间】 按照使用rfc3339所定义的格式，格式为yyyy-MM-DDThh:mm:ss+TIMEZONE
+   */
+  @SerializedName("update_time")
+  private String updateTime;
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsGetResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsGetResult.java
new file mode 100644
index 0000000000..2e24a4a3c6
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsGetResult.java
@@ -0,0 +1,103 @@
+package com.github.binarywang.wxpay.bean.transfer;
+
+import com.github.binarywang.wxpay.constant.WxPayConstants;
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * <pre>
+ * 商家转账到零钱查询转账单接口
+ * 文档地址：https://pay.weixin.qq.com/doc/v3/merchant/4012716457 https://pay.weixin.qq.com/doc/v3/merchant/4012716437
+ * </pre>
+ *
+ * @author Nor
+ * @date 2025/1/17
+ */
+@Data
+@NoArgsConstructor
+public class TransferBillsGetResult implements Serializable {
+  private static final long serialVersionUID = -6376955113492371763L;
+
+  /**
+   * 【商户号】 微信支付分配的商户号
+   */
+  @SerializedName("mch_id")
+  private String mchId;
+
+  /**
+   * 【商户单号】 商户系统内部的商家单号，要求此参数只能由数字、大小写字母组成，在商户系统内部唯一
+   */
+  @SerializedName("out_bill_no")
+  private String outBillNo;
+
+  /**
+   * 【商家转账订单号】 商家转账订单的主键，唯一定义此资源的标识
+   */
+  @SerializedName("transfer_bill_no")
+  private String transferBillNo;
+
+  /**
+   * 【商户AppID】 申请商户号的AppID或商户号绑定的AppID（企业号corpid即为此AppID）
+   */
+  private String appid;
+
+  /**
+   * 【单据状态】
+   * 可选取值
+   * ACCEPTED: 转账已受理
+   * PROCESSING: 转账处理中，转账结果尚未明确，如一直处于此状态，建议检查账户余额是否足够
+   * WAIT_USER_CONFIRM: 待收款用户确认，可拉起微信收款确认页面进行收款确认
+   * TRANSFERING: 转账结果尚未明确，可拉起微信收款确认页面再次重试确认收款
+   * SUCCESS: 转账成功
+   * FAIL: 转账失败
+   * CANCELING: 商户撤销请求受理成功，该笔转账正在撤销中
+   * CANCELLED: 转账撤销完成
+   *
+   * @see WxPayConstants.TransformBillState
+   */
+  private String state;
+
+  /**
+   * 【转账金额】 转账金额单位为“分”。
+   */
+  @SerializedName("transfer_amount")
+  private String transferAmount;
+
+  /**
+   * 【转账备注】 单条转账备注（微信用户会收到该备注），UTF8编码，最多允许32个字符
+   */
+  @SerializedName("transfer_remark")
+  private String transferRemark;
+
+  /**
+   * 【失败原因】 订单已失败或者已退资金时，返回失败原因
+   */
+  @SerializedName("fail_reason")
+  private String failReason;
+
+  /**
+   * 【收款用户OpenID】 商户AppID下，某用户的OpenID
+   */
+  private String openid;
+
+  /**
+   * 【收款用户姓名】 收款方真实姓名。支持标准RSA算法和国密算法，公钥由微信侧提供转账金额 >= 2,000元时，该笔明细必须填写若商户传入收款用户姓名，微信支付会校验用户OpenID与姓名是否一致，并提供电子回单
+   */
+  @SerializedName("user_name")
+  private String userName;
+
+  /**
+   * 【单据创建时间】 单据受理成功时返回，按照使用rfc3339所定义的格式，格式为yyyy-MM-DDThh:mm:ss+TIMEZONE
+   */
+  @SerializedName("create_time")
+  private String createTime;
+
+  /**
+   * 【最后一次状态变更时间】 单据最后更新时间，按照使用rfc3339所定义的格式，格式为yyyy-MM-DDThh:mm:ss+TIMEZONE
+   */
+  @SerializedName("update_time")
+  private String updateTime;
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsNotifyResult.java
new file mode 100644
index 0000000000..80709a1022
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsNotifyResult.java
@@ -0,0 +1,79 @@
+package com.github.binarywang.wxpay.bean.transfer;
+
+import com.github.binarywang.wxpay.bean.notify.OriginNotifyResponse;
+import com.github.binarywang.wxpay.bean.notify.WxPayBaseNotifyV3Result;
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ *  <pre>
+ *    商家转账到零钱接口将转账结果通知用户
+ *    文档地址：https://pay.weixin.qq.com/doc/v3/merchant/4012716434
+ *  </pre>
+ */
+@Data
+public class TransferBillsNotifyResult implements Serializable, WxPayBaseNotifyV3Result<TransferBillsNotifyResult.DecryptNotifyResult> {
+  /**
+   * 源数据
+   */
+  private OriginNotifyResponse rawData;
+  /**
+   * 解密后的数据
+   */
+  private TransferBillsNotifyResult.DecryptNotifyResult result;
+
+  @Data
+  @NoArgsConstructor
+  public static class DecryptNotifyResult implements Serializable {
+    /**
+     * 商户号
+     */
+    @SerializedName(value = "mch_id")
+    private String mchId;
+    /**
+     * 商家批次单号
+     */
+    @SerializedName(value = "out_bill_no")
+    private String outBillNo;
+    /**
+     * 微信批次单号
+     */
+    @SerializedName(value = "transfer_bill_no")
+    private String transferBillNo;
+    /**
+     * 批次状态
+     */
+    @SerializedName(value = "state")
+    private String state;
+    /**
+     * 转账金额
+     */
+    @SerializedName(value = "transfer_amount")
+    private Integer transferAmount;
+
+    /**
+     * 批次状态
+     */
+    @SerializedName(value = "openid")
+    private String openid;
+
+    /**
+     * 单据创建时间
+     */
+    @SerializedName(value = "create_time")
+    private String createTime;
+    /**
+     * 最后一次状态变更时间
+     */
+    @SerializedName(value = "update_time")
+    private String updateTime;
+    /**
+     * 错误原因
+     */
+    @SerializedName(value = "fail_reason")
+    private String failReason;
+  }
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsRequest.java
new file mode 100644
index 0000000000..230e564e4b
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsRequest.java
@@ -0,0 +1,108 @@
+package com.github.binarywang.wxpay.bean.transfer;
+
+import com.github.binarywang.wxpay.v3.SpecEncrypt;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 发起商家转账API参数
+ *
+ * @author allovine
+ * created on  2025/1/15
+ **/
+@Data
+@Builder(builderMethodName = "newBuilder")
+@NoArgsConstructor
+@AllArgsConstructor
+public class TransferBillsRequest implements Serializable {
+  private static final long serialVersionUID = -2175582517588397437L;
+
+  /**
+   * 直连商户的appid
+   */
+  @SerializedName("appid")
+  private String appid;
+
+  /**
+   * 商户系统内部的商家单号
+   */
+  @SerializedName("out_bill_no")
+  private String outBillNo;
+
+  /**
+   * 转账场景ID
+   * 商户平台-产品中心-商家转账 申请
+   * 佣金报酬 ID:1005
+   */
+  @SerializedName("transfer_scene_id")
+  private String transferSceneId;
+
+  /**
+   * 用户在直连商户应用下的用户标示
+   */
+  @SerializedName("openid")
+  private String openid;
+
+  /**
+   * 收款用户姓名
+   */
+  @SpecEncrypt
+  @SerializedName("user_name")
+  private String userName;
+
+  /**
+   * 转账金额
+   */
+  @SerializedName("transfer_amount")
+  private Integer transferAmount;
+
+  /**
+   * 转账备注
+   */
+  @SerializedName("transfer_remark")
+  private String transferRemark;
+
+  /**
+   * 异步接收微信支付结果通知的回调地址，通知url必须为公网可访问的url，必须为https，不能携带参数
+   */
+  @SerializedName("notify_url")
+  private String notifyUrl;
+
+  /**
+   * 用户收款感知
+   */
+  @SerializedName("user_recv_perception")
+  private String userRecvPerception;
+
+
+  /**
+   * 转账场景报备信息
+   */
+  @SerializedName("transfer_scene_report_infos")
+  private List<TransferSceneReportInfo> transferSceneReportInfos;
+
+
+  @Data
+  @Builder(builderMethodName = "newBuilder")
+  @AllArgsConstructor
+  @NoArgsConstructor
+  public static class TransferSceneReportInfo {
+    /**
+     * 信息类型
+     */
+    @SerializedName("info_type")
+    private String infoType;
+
+    /**
+     * 信息内容
+     */
+    @SerializedName("info_content")
+    private String infoContent;
+  }
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsResult.java
new file mode 100644
index 0000000000..78e0aec6ab
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBillsResult.java
@@ -0,0 +1,58 @@
+package com.github.binarywang.wxpay.bean.transfer;
+
+import com.github.binarywang.wxpay.constant.WxPayConstants;
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 商家转账结果
+ *
+ * @author allovine
+ * created on  2025/1/15
+ **/
+@Data
+@NoArgsConstructor
+public class TransferBillsResult implements Serializable {
+  private static final long serialVersionUID = -2175582517588397437L;
+
+  /**
+   * 商户单号
+   */
+  @SerializedName("out_bill_no")
+  private String outBillNo;
+
+  /**
+   * 微信转账单号
+   */
+  @SerializedName("transfer_bill_no")
+  private String transferBillNo;
+
+  /**
+   * 单据创建时间
+   */
+  @SerializedName("create_time")
+  private String createTime;
+
+  /**
+   * 单据状态
+   *
+   * @see WxPayConstants.TransformBillState
+   */
+  @SerializedName("state")
+  private String state;
+
+  /**
+   * 失败原因
+   */
+  @SerializedName("fail_reason")
+  private String failReason;
+
+  /**
+   * 跳转领取页面的package信息
+   */
+  @SerializedName("package_info")
+  private String packageInfo;
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/VerifierBuilder.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/VerifierBuilder.java
new file mode 100644
index 0000000000..b0d9276a32
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/VerifierBuilder.java
@@ -0,0 +1,141 @@
+package com.github.binarywang.wxpay.config;
+
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.v3.auth.*;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+import java.nio.charset.StandardCharsets;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * 验证器构建.
+ *
+ * @author holy
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+class VerifierBuilder {
+  /**
+   * 构建验证器.
+   * <p>
+   * 场景
+   * <pre>
+   *   1. 老商户号，只有平台证书，未开通公钥 （已验证）
+   *   2. 新商户号，被强制开通公钥，没有平台证书 （已验证）
+   *   3. 老商户号，有平台证书，主动开通公钥 （未验证，具备条件的朋友，可以帮忙验证下）
+   *   ...
+   * </pre>
+   *
+   * @param certSerialNo       c
+   * @param mchId              m
+   * @param apiV3Key           a
+   * @param merchantPrivateKey m
+   * @param wxPayHttpProxy     w
+   * @param certAutoUpdateTime c
+   * @param payBaseUrl         p
+   * @param publicKeyId        p
+   * @param publicKey          p
+   * @return v
+   * @throws WxPayException e
+   */
+  @SuppressWarnings("java:S107")
+  static Verifier build(
+    // 平台证书 - 依赖参数
+    String certSerialNo,
+    String mchId,
+    String apiV3Key,
+    PrivateKey merchantPrivateKey,
+    WxPayHttpProxy wxPayHttpProxy,
+    int certAutoUpdateTime,
+    String payBaseUrl,
+    // 公钥 - 依赖参数
+    String publicKeyId,
+    PublicKey publicKey
+  ) throws WxPayException {
+    Verifier certificatesVerifier = null;
+    Exception ex = null;
+
+    // 构建平台证书验证器
+    // （沿用旧逻辑）优先构建平台证书验证器，因为公钥验证器需要平台证书验证器 (见以下 .setOtherVerifier )
+    // 新商户号默认无平台证书，已确认无法构建平台证书验证器，会抛出异常；老商户号，有平台证书主动开通公钥的情况，待具备条件的朋友验证
+    // 建议公钥模式稳定后，优先构建公钥验证器，以免每次都尝试构建平台证书验证器，且失败 {@link com.github.binarywang.wxpay.v3.auth.PublicCertificateVerifier.verify}
+    if (merchantPrivateKey != null && StringUtils.isNoneBlank(certSerialNo, apiV3Key)) {
+      try {
+        certificatesVerifier = getCertificatesVerifier(
+          certSerialNo, mchId, apiV3Key, merchantPrivateKey, wxPayHttpProxy, certAutoUpdateTime, payBaseUrl
+        );
+      } catch (Exception e) {
+        ex = e;
+      }
+    }
+
+    // 构建公钥验证器
+    if (publicKey != null && StringUtils.isNotBlank(publicKeyId)) {
+      try {
+        certificatesVerifier = getPublicCertVerifier(publicKeyId, publicKey, certificatesVerifier);
+      } catch (Exception e) {
+        ex = e;
+      }
+    }
+    if (certificatesVerifier != null) {
+      return certificatesVerifier;
+    }
+
+    // 有异常时抛出
+    if (ex != null) {
+      throw new WxPayException(ex.getMessage(), ex);
+    }
+
+    // 没有证书验证器时。不确定是否抛出异常，沿用之前逻辑，返回 null
+    return null;
+  }
+
+  /**
+   * 针对完全使用公钥的场景
+   * @param publicKeyId 公钥id
+   * @param publicKey 公钥
+   * @return
+   */
+  static Verifier buildPublicCertVerifier(String publicKeyId, PublicKey publicKey) {
+    return getPublicCertVerifier(publicKeyId, publicKey, null);
+  }
+
+  /**
+   * 获取证书验证器.
+   *
+   * @param certSerialNo       certSerialNo
+   * @param mchId              mchId
+   * @param apiV3Key           apiV3Key
+   * @param merchantPrivateKey merchantPrivateKey
+   * @param wxPayHttpProxy     wxPayHttpProxy
+   * @param certAutoUpdateTime certAutoUpdateTime
+   * @param payBaseUrl         payBaseUrl
+   * @return verifier
+   */
+  private static AutoUpdateCertificatesVerifier getCertificatesVerifier(
+    String certSerialNo, String mchId, String apiV3Key, PrivateKey merchantPrivateKey,
+    WxPayHttpProxy wxPayHttpProxy, int certAutoUpdateTime, String payBaseUrl
+  ) {
+    return new AutoUpdateCertificatesVerifier(
+      new WxPayCredentials(mchId, new PrivateKeySigner(certSerialNo, merchantPrivateKey)),
+      apiV3Key.getBytes(StandardCharsets.UTF_8), certAutoUpdateTime,
+      payBaseUrl, wxPayHttpProxy);
+  }
+
+  /**
+   * 获取公钥验证器.
+   *
+   * @param publicKeyId          id
+   * @param publicKey            key
+   * @param certificatesVerifier verifier
+   * @return verifier
+   */
+  private static Verifier getPublicCertVerifier(String publicKeyId, PublicKey publicKey, Verifier certificatesVerifier) {
+    Verifier publicCertificatesVerifier = new PublicCertificateVerifier(publicKey, publicKeyId);
+    publicCertificatesVerifier.setOtherVerifier(certificatesVerifier);
+    certificatesVerifier = publicCertificatesVerifier;
+    return certificatesVerifier;
+  }
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java
index 637d46e986..01f9cd534f 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/WxPayConfig.java
@@ -4,7 +4,8 @@
 import com.github.binarywang.wxpay.util.HttpProxyUtils;
 import com.github.binarywang.wxpay.util.ResourcesUtils;
 import com.github.binarywang.wxpay.v3.WxPayV3HttpClientBuilder;
-import com.github.binarywang.wxpay.v3.auth.*;
+import com.github.binarywang.wxpay.v3.auth.Verifier;
+import com.github.binarywang.wxpay.v3.auth.WxPayValidator;
 import com.github.binarywang.wxpay.v3.util.PemUtils;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
@@ -13,15 +14,24 @@
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.RegExUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpHost;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.impl.client.BasicCredentialsProvider;
 import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.conn.ssl.DefaultHostnameVerifier;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
 import org.apache.http.ssl.SSLContexts;
 
 import javax.net.ssl.SSLContext;
 import java.io.*;
 import java.net.URL;
-import java.nio.charset.StandardCharsets;
 import java.security.KeyStore;
 import java.security.PrivateKey;
+import java.security.PublicKey;
 import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
 import java.util.Base64;
@@ -138,6 +148,25 @@ public class WxPayConfig {
    */
   private byte[] privateCertContent;
 
+  /**
+   * 公钥ID
+   */
+  private String publicKeyId;
+
+  /**
+   * pub_key.pem证书base64编码
+   */
+  private String publicKeyString;
+
+  /**
+   * pub_key.pem证书文件的绝对路径或者以classpath:开头的类路径.
+   */
+  private String publicKeyPath;
+
+  /**
+   * pub_key.pem证书文件内容的字节数组.
+   */
+  private byte[] publicKeyContent;
   /**
    * apiV3 秘钥值.
    */
@@ -165,11 +194,32 @@ public class WxPayConfig {
 
 
   private CloseableHttpClient apiV3HttpClient;
+  
+  /**
+   * 用于普通支付接口的可复用HttpClient，使用连接池
+   */
+  private CloseableHttpClient httpClient;
+  
+  /**
+   * 用于需要SSL证书的支付接口的可复用HttpClient，使用连接池
+   */
+  private CloseableHttpClient sslHttpClient;
+  
   /**
    * 支持扩展httpClientBuilder
    */
   private HttpClientBuilderCustomizer httpClientBuilderCustomizer;
   private HttpClientBuilderCustomizer apiV3HttpClientBuilderCustomizer;
+  
+  /**
+   * HTTP连接池最大连接数，默认20
+   */
+  private int maxConnTotal = 20;
+  
+  /**
+   * HTTP连接池每个路由的最大连接数，默认10
+   */
+  private int maxConnPerRoute = 10;
   /**
    * 私钥信息
    */
@@ -207,6 +257,16 @@ public class WxPayConfig {
    */
   private Verifier verifier;
 
+  /**
+   * 是否将全部v3接口的请求都添加Wechatpay-Serial请求头，默认不添加
+   */
+  private boolean strictlyNeedWechatPaySerial = false;
+
+  /**
+   * 是否完全使用公钥模式(用以微信从平台证书到公钥的灰度切换)，默认不使用
+   */
+  private boolean fullPublicKeyModel = false;
+
   /**
    * 返回所设置的微信支付接口请求地址域名.
    *
@@ -241,7 +301,7 @@ public SSLContext initSSLContext() throws WxPayException {
     }
 
     try (InputStream inputStream = this.loadConfigInputStream(this.keyString, this.getKeyPath(),
-      this.keyContent, "p12证书");) {
+      this.keyContent, "p12证书")) {
       KeyStore keystore = KeyStore.getInstance("PKCS12");
       char[] partnerId2charArray = this.getMchId().toCharArray();
       keystore.load(inputStream, partnerId2charArray);
@@ -264,29 +324,20 @@ public CloseableHttpClient initApiV3HttpClient() throws WxPayException {
     if (StringUtils.isBlank(this.getApiV3Key())) {
       throw new WxPayException("请确保apiV3Key值已设置");
     }
-
-    // 尝试从p12证书中加载私钥和证书
-    PrivateKey merchantPrivateKey = null;
-    X509Certificate certificate = null;
-    Object[] objects = this.p12ToPem();
-    if (objects != null) {
-      merchantPrivateKey = (PrivateKey) objects[0];
-      certificate = (X509Certificate) objects[1];
-      this.certSerialNo = certificate.getSerialNumber().toString(16).toUpperCase();
-    }
     try {
-      if (merchantPrivateKey == null) {
-        if (StringUtils.isNotBlank(this.getPrivateKeyString())) {
-          this.setPrivateKeyString(Base64.getEncoder().encodeToString(this.getPrivateKeyString().getBytes()));
-        }
-
-        try (InputStream keyInputStream = this.loadConfigInputStream(this.getPrivateKeyString(), this.getPrivateKeyPath(),
-          this.privateKeyContent, "privateKeyPath")) {
-          merchantPrivateKey = PemUtils.loadPrivateKey(keyInputStream);
-        }
-
+      PrivateKey merchantPrivateKey = null;
+      PublicKey publicKey = null;
+
+      // 不使用完全公钥模式时，同时兼容平台证书和公钥
+      X509Certificate certificate = null;
+      // 尝试从p12证书中加载私钥和证书
+      Object[] objects = this.p12ToPem();
+      if (objects != null) {
+        merchantPrivateKey = (PrivateKey) objects[0];
+        certificate = (X509Certificate) objects[1];
+        this.certSerialNo = certificate.getSerialNumber().toString(16).toUpperCase();
       }
-      if (certificate == null && StringUtils.isBlank(this.getCertSerialNo())) {
+      if (certificate == null && StringUtils.isBlank(this.getCertSerialNo()) && StringUtils.isNotBlank(this.getPrivateCertPath())) {
         try (InputStream certInputStream = this.loadConfigInputStream(this.getPrivateCertString(), this.getPrivateCertPath(),
           this.privateCertContent, "privateCertPath")) {
           certificate = PemUtils.loadCertificate(certInputStream);
@@ -294,12 +345,38 @@ public CloseableHttpClient initApiV3HttpClient() throws WxPayException {
         this.certSerialNo = certificate.getSerialNumber().toString(16).toUpperCase();
       }
 
+      if (this.getPublicKeyString() != null || this.getPublicKeyPath() != null || this.publicKeyContent != null) {
+        if (StringUtils.isBlank(this.getPublicKeyId())) {
+          throw new WxPayException("请确保和publicKeyId配套使用");
+        }
+        try (InputStream pubInputStream =
+               this.loadConfigInputStream(this.getPublicKeyString(), this.getPublicKeyPath(),
+                 this.publicKeyContent, "publicKeyPath")) {
+          publicKey = PemUtils.loadPublicKey(pubInputStream);
+        }
+      }
+
+      // 加载api私钥
+      if (merchantPrivateKey == null && (StringUtils.isNotBlank(this.getPrivateKeyPath()) || StringUtils.isNotBlank(this.getPrivateKeyString()) || null != this.privateKeyContent)) {
+        try (InputStream keyInputStream = this.loadConfigInputStream(this.getPrivateKeyString(), this.getPrivateKeyPath(),
+          this.privateKeyContent, "privateKeyPath")) {
+          merchantPrivateKey = PemUtils.loadPrivateKey(keyInputStream);
+        }
+      }
+
       //构造Http Proxy正向代理
       WxPayHttpProxy wxPayHttpProxy = getWxPayHttpProxy();
 
-      AutoUpdateCertificatesVerifier certificatesVerifier = new AutoUpdateCertificatesVerifier(
-        new WxPayCredentials(mchId, new PrivateKeySigner(certSerialNo, merchantPrivateKey)),
-        this.getApiV3Key().getBytes(StandardCharsets.UTF_8), this.getCertAutoUpdateTime(), this.getPayBaseUrl(), wxPayHttpProxy);
+      // 构造证书验签器
+      Verifier certificatesVerifier;
+      if (this.fullPublicKeyModel) {
+        // 使用完全公钥模式时，只加载公钥相关配置，避免下载平台证书使灰度切换无法达到100%覆盖
+        certificatesVerifier = VerifierBuilder.buildPublicCertVerifier(this.publicKeyId, publicKey);
+      } else {
+        certificatesVerifier = VerifierBuilder.build(
+          this.getCertSerialNo(), this.getMchId(), this.getApiV3Key(), merchantPrivateKey, wxPayHttpProxy,
+          this.getCertAutoUpdateTime(), this.getPayBaseUrl(), this.getPublicKeyId(), publicKey);
+      }
 
       WxPayV3HttpClientBuilder wxPayV3HttpClientBuilder = WxPayV3HttpClientBuilder.create()
         .withMerchant(mchId, certSerialNo, merchantPrivateKey)
@@ -337,21 +414,32 @@ private WxPayHttpProxy getWxPayHttpProxy() {
     return null;
   }
 
+  /**
+   * 从指定参数加载输入流
+   *
+   * @param configString  证书内容进行Base64加密后的字符串
+   * @param configPath    证书路径
+   * @param configContent 证书内容的字节数组
+   * @param certName      证书的标识
+   * @return 输入流
+   * @throws WxPayException 异常
+   */
   private InputStream loadConfigInputStream(String configString, String configPath, byte[] configContent,
-                                            String fileName) throws WxPayException {
-    InputStream inputStream;
+                                            String certName) throws WxPayException {
     if (configContent != null) {
-      inputStream = new ByteArrayInputStream(configContent);
-    } else if (StringUtils.isNotEmpty(configString)) {
-      configContent = configString.getBytes(StandardCharsets.UTF_8);
-      inputStream = new ByteArrayInputStream(configContent);
-    } else {
-      if (StringUtils.isBlank(configPath)) {
-        throw new WxPayException("请确保证书文件地址【" + fileName + "】或者内容已配置");
-      }
-      inputStream = this.loadConfigInputStream(configPath);
+      return new ByteArrayInputStream(configContent);
     }
-    return inputStream;
+
+    if (StringUtils.isNotEmpty(configString)) {
+      configContent = Base64.getDecoder().decode(configString);
+      return new ByteArrayInputStream(configContent);
+    }
+
+    if (StringUtils.isBlank(configPath)) {
+      throw new WxPayException(String.format("请确保【%s】的文件地址【%s】存在", certName, configPath));
+    }
+
+    return this.loadConfigInputStream(configPath);
   }
 
 
@@ -416,13 +504,14 @@ private InputStream loadConfigInputStream(String configPath) throws WxPayExcepti
    */
   private Object[] p12ToPem() {
     String key = getMchId();
-    if (StringUtils.isBlank(key)) {
+    if (StringUtils.isBlank(key) ||
+      (StringUtils.isBlank(this.getKeyPath()) && this.keyContent == null && StringUtils.isBlank(this.keyString))) {
       return null;
     }
 
     // 分解p12证书文件
     try (InputStream inputStream = this.loadConfigInputStream(this.keyString, this.getKeyPath(),
-      this.keyContent, "p12证书");) {
+      this.keyContent, "p12证书")) {
       KeyStore keyStore = KeyStore.getInstance("PKCS12");
       keyStore.load(inputStream, key.toCharArray());
 
@@ -433,10 +522,117 @@ private Object[] p12ToPem() {
       X509Certificate x509Certificate = (X509Certificate) certificate;
       return new Object[]{privateKey, x509Certificate};
     } catch (Exception e) {
-      log.error("加载证书时发生异常", e);
+      log.error("加载p12证书时发生异常", e);
     }
 
     return null;
 
   }
+
+  /**
+   * 初始化使用连接池的HttpClient
+   * 
+   * @return CloseableHttpClient
+   * @throws WxPayException 初始化异常
+   */
+  public CloseableHttpClient initHttpClient() throws WxPayException {
+    if (this.httpClient != null) {
+      return this.httpClient;
+    }
+    
+    // 创建连接池管理器
+    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
+    connectionManager.setMaxTotal(this.maxConnTotal);
+    connectionManager.setDefaultMaxPerRoute(this.maxConnPerRoute);
+    
+    // 创建HttpClient构建器
+    org.apache.http.impl.client.HttpClientBuilder httpClientBuilder = HttpClients.custom()
+        .setConnectionManager(connectionManager);
+        
+    // 配置代理
+    configureProxy(httpClientBuilder);
+    
+    // 提供自定义httpClientBuilder的能力
+    Optional.ofNullable(httpClientBuilderCustomizer).ifPresent(e -> {
+      e.customize(httpClientBuilder);
+    });
+    
+    this.httpClient = httpClientBuilder.build();
+    return this.httpClient;
+  }
+
+  /**
+   * 初始化使用连接池且支持SSL的HttpClient
+   * 
+   * @return CloseableHttpClient
+   * @throws WxPayException 初始化异常
+   */
+  public CloseableHttpClient initSslHttpClient() throws WxPayException {
+    if (this.sslHttpClient != null) {
+      return this.sslHttpClient;
+    }
+    
+    // 初始化SSL上下文
+    SSLContext sslContext = this.getSslContext();
+    if (null == sslContext) {
+      sslContext = this.initSSLContext();
+    }
+    
+    // 创建支持SSL的连接池管理器
+    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
+    connectionManager.setMaxTotal(this.maxConnTotal);
+    connectionManager.setDefaultMaxPerRoute(this.maxConnPerRoute);
+    
+    // 创建HttpClient构建器，配置SSL
+    org.apache.http.impl.client.HttpClientBuilder httpClientBuilder = HttpClients.custom()
+        .setConnectionManager(connectionManager)
+        .setSSLSocketFactory(new SSLConnectionSocketFactory(sslContext, new DefaultHostnameVerifier()));
+        
+    // 配置代理
+    configureProxy(httpClientBuilder);
+    
+    // 提供自定义httpClientBuilder的能力
+    Optional.ofNullable(httpClientBuilderCustomizer).ifPresent(e -> {
+      e.customize(httpClientBuilder);
+    });
+    
+    this.sslHttpClient = httpClientBuilder.build();
+    return this.sslHttpClient;
+  }
+
+  /**
+   * 配置HTTP代理
+   */
+  private void configureProxy(org.apache.http.impl.client.HttpClientBuilder httpClientBuilder) {
+    if (StringUtils.isNotBlank(this.getHttpProxyHost()) && this.getHttpProxyPort() > 0) {
+      if (StringUtils.isEmpty(this.getHttpProxyUsername())) {
+        this.setHttpProxyUsername("whatever");
+      }
+
+      // 使用代理服务器 需要用户认证的代理服务器
+      CredentialsProvider provider = new BasicCredentialsProvider();
+      provider.setCredentials(new AuthScope(this.getHttpProxyHost(), this.getHttpProxyPort()),
+        new UsernamePasswordCredentials(this.getHttpProxyUsername(), this.getHttpProxyPassword()));
+      httpClientBuilder.setDefaultCredentialsProvider(provider)
+        .setProxy(new HttpHost(this.getHttpProxyHost(), this.getHttpProxyPort()));
+    }
+  }
+
+  /**
+   * 获取用于普通支付接口的HttpClient
+   * 
+   * @return CloseableHttpClient
+   */
+  public CloseableHttpClient getHttpClient() {
+    return httpClient;
+  }
+
+  /**
+   * 获取用于SSL支付接口的HttpClient
+   * 
+   * @return CloseableHttpClient
+   */
+  public CloseableHttpClient getSslHttpClient() {
+    return sslHttpClient;
+  }
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java
index 819cdfe731..e8a6b6acb3 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/constant/WxPayConstants.java
@@ -6,6 +6,7 @@
 import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult;
 import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult;
 import com.google.common.collect.Lists;
+import lombok.experimental.UtilityClass;
 import org.apache.commons.lang3.time.FastDateFormat;
 
 import java.text.Format;
@@ -353,4 +354,86 @@ public static class ReceiverType {
     public static final String PERSONAL_SUB_OPENID = "PERSONAL_SUB_OPENID";
   }
 
+  /**
+   * 微信商户转账订单状态
+   */
+  @UtilityClass
+  public static class TransformBillState {
+    /**
+     * 转账已受理
+     */
+    public static final String ACCEPTED = "ACCEPTED";
+
+    /**
+     * 转账处理中，转账结果尚未明确，如一直处于此状态，建议检查账户余额是否足够
+     */
+    public static final String PROCESSING = "PROCESSING";
+
+    /**
+     * 待收款用户确认，可拉起微信收款确认页面进行收款确认
+     */
+    public static final String WAIT_USER_CONFIRM = "WAIT_USER_CONFIRM";
+
+    /**
+     * 转账结果尚未明确，可拉起微信收款确认页面再次重试确认收款
+     */
+    public static final String TRANSFERING = "TRANSFERING";
+
+    /**
+     * 转账成功
+     */
+    public static final String SUCCESS = "SUCCESS";
+
+    /**
+     * 转账失败
+     */
+    public static final String FAIL = "FAIL";
+
+    /**
+     * 商户撤销请求受理成功，该笔转账正在撤销中
+     */
+    public static final String CANCELING = "CANCELING";
+
+    /**
+     * 转账撤销完成
+     */
+    public static final String CANCELLED = "CANCELLED";
+
+  }
+
+  /**
+   * 【转账场景ID】 该笔转账使用的转账场景，可前往“商户平台-产品中心-商家转账”中申请。
+   */
+  @UtilityClass
+  public static class TransformSceneId {
+    /**
+     * 现金营销
+     */
+    public static final String CASH_MARKETING = "1001";
+  }
+
+  /**
+   * 用户收款感知
+   *
+   * @see <a href="https://pay.weixin.qq.com/doc/v3/merchant/4012711988#3.3-%E5%8F%91%E8%B5%B7%E8%BD%AC%E8%B4%A6">官方文档</a>
+   */
+  @UtilityClass
+  public static class UserRecvPerception {
+    /**
+     * 转账场景 现金营销
+     * 场景介绍 向参与营销活动的用户发放现金奖励
+     */
+    public static class CASH_MARKETING {
+      /**
+       * 默认展示
+       */
+      public static final String ACTIVITY = "活动奖励";
+
+      /**
+       * 需在发起转账时，“用户收款感知”字段主动传入“现金奖励”才可展示
+       */
+      public static final String CASH = "现金奖励";
+    }
+
+  }
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/converter/WxPayOrderNotifyResultConverter.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/converter/WxPayOrderNotifyResultConverter.java
index 0f01358633..e3e28e9183 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/converter/WxPayOrderNotifyResultConverter.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/converter/WxPayOrderNotifyResultConverter.java
@@ -39,7 +39,6 @@ public WxPayOrderNotifyResultConverter(Mapper mapper, ReflectionProvider reflect
   }
 
   @Override
-  @SuppressWarnings("rawtypes")
   public boolean canConvert(Class type) {
     return type.equals(WxPayOrderNotifyResult.class);
   }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/example/NewTransferApiExample.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/example/NewTransferApiExample.java
new file mode 100644
index 0000000000..8d74e5a4ef
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/example/NewTransferApiExample.java
@@ -0,0 +1,249 @@
+package com.github.binarywang.wxpay.example;
+
+import com.github.binarywang.wxpay.bean.notify.SignatureHeader;
+import com.github.binarywang.wxpay.bean.transfer.*;
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.TransferService;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
+
+/**
+ * 新版商户转账API使用示例
+ * 
+ * 从2025年1月15日开始，微信支付推出了新版的商户转账API
+ * 新开通的商户号只能使用最新版本的商户转账接口
+ * 
+ * @author WxJava Team
+ * @since 2025-01-15
+ */
+public class NewTransferApiExample {
+
+    private final TransferService transferService;
+
+    public NewTransferApiExample(WxPayConfig config) {
+        // 初始化微信支付服务
+        WxPayService wxPayService = new WxPayServiceImpl();
+        wxPayService.setConfig(config);
+        
+        // 获取新版转账服务
+        this.transferService = wxPayService.getTransferService();
+    }
+
+    /**
+     * 发起单笔转账示例
+     * 新版API使用 /v3/fund-app/mch-transfer/transfer-bills 接口
+     */
+    public void transferExample() {
+        try {
+            // 构建转账请求
+            TransferBillsRequest request = TransferBillsRequest.newBuilder()
+                .appid("wx1234567890123456")                    // 应用ID
+                .outBillNo("TRANSFER_" + System.currentTimeMillis()) // 商户转账单号，确保唯一
+                .transferSceneId("1005")                       // 转账场景ID（1005=佣金报酬）
+                .openid("oUpF8uMuAJO_M2pxb1Q9zNjWeS6o")       // 收款用户的openid
+                .userName("张三")                               // 收款用户真实姓名（可选，会自动加密）
+                .transferAmount(100)                           // 转账金额，单位：分（此处为1元）
+                .transferRemark("佣金报酬")                     // 转账备注，用户可见
+                .notifyUrl("https://your-domain.com/transfer/notify") // 异步通知地址（可选）
+                .userRecvPerception("Y")                       // 用户收款感知：Y=会收到通知，N=不会收到通知
+                .build();
+
+            // 发起转账
+            TransferBillsResult result = transferService.transferBills(request);
+
+            // 输出结果
+            System.out.println("=== 转账发起成功 ===");
+            System.out.println("商户单号: " + result.getOutBillNo());
+            System.out.println("微信转账单号: " + result.getTransferBillNo());
+            System.out.println("创建时间: " + result.getCreateTime());
+            System.out.println("状态: " + result.getState());
+            System.out.println("跳转领取页面信息: " + result.getPackageInfo());
+
+        } catch (WxPayException e) {
+            System.err.println("转账失败: " + e.getMessage());
+            System.err.println("错误代码: " + e.getErrCode());
+            System.err.println("错误描述: " + e.getErrCodeDes());
+        }
+    }
+
+    /**
+     * 通过商户单号查询转账结果
+     */
+    public void queryByOutBillNoExample() {
+        try {
+            String outBillNo = "TRANSFER_1642567890123";
+            TransferBillsGetResult result = transferService.getBillsByOutBillNo(outBillNo);
+
+            System.out.println("=== 查询转账结果（商户单号）===");
+            System.out.println("商户单号: " + result.getOutBillNo());
+            System.out.println("微信转账单号: " + result.getTransferBillNo());
+            System.out.println("状态: " + result.getState());
+            System.out.println("转账金额: " + result.getTransferAmount() + "分");
+            System.out.println("用户openid: " + result.getOpenid());
+            System.out.println("转账备注: " + result.getTransferRemark());
+
+        } catch (WxPayException e) {
+            System.err.println("查询失败: " + e.getMessage());
+        }
+    }
+
+    /**
+     * 通过微信转账单号查询转账结果
+     */
+    public void queryByTransferBillNoExample() {
+        try {
+            String transferBillNo = "1000000000000000000000000001";
+            TransferBillsGetResult result = transferService.getBillsByTransferBillNo(transferBillNo);
+
+            System.out.println("=== 查询转账结果（微信单号）===");
+            System.out.println("微信转账单号: " + result.getTransferBillNo());
+            System.out.println("状态: " + result.getState());
+            System.out.println("失败原因: " + result.getFailReason());
+
+        } catch (WxPayException e) {
+            System.err.println("查询失败: " + e.getMessage());
+        }
+    }
+
+    /**
+     * 撤销转账示例
+     * 注意：只有在特定状态下才能撤销
+     */
+    public void cancelTransferExample() {
+        try {
+            String outBillNo = "TRANSFER_1642567890123";
+            TransferBillsCancelResult result = transferService.transformBillsCancel(outBillNo);
+
+            System.out.println("=== 撤销转账结果 ===");
+            System.out.println("商户单号: " + result.getOutBillNo());
+            System.out.println("状态: " + result.getState());
+            System.out.println("更新时间: " + result.getUpdateTime());
+
+        } catch (WxPayException e) {
+            System.err.println("撤销失败: " + e.getMessage());
+        }
+    }
+
+    /**
+     * 处理转账回调通知示例
+     * 这个方法通常在您的Web服务器的回调接口中调用
+     */
+    public void handleNotifyExample(String notifyData, String timestamp, String nonce, String signature, String serial) {
+        try {
+            // 构建签名头信息
+            SignatureHeader header = new SignatureHeader();
+            header.setTimeStamp(timestamp);
+            header.setNonce(nonce);
+            header.setSignature(signature);
+            header.setSerial(serial);
+
+            // 解析并验签回调数据
+            TransferBillsNotifyResult notifyResult = transferService.parseTransferBillsNotifyResult(notifyData, header);
+
+            System.out.println("=== 处理转账回调通知 ===");
+            System.out.println("商户单号: " + notifyResult.getResult().getOutBillNo());
+            System.out.println("微信转账单号: " + notifyResult.getResult().getTransferBillNo());
+            System.out.println("状态: " + notifyResult.getResult().getState());
+            System.out.println("转账金额: " + notifyResult.getResult().getTransferAmount() + "分");
+            System.out.println("更新时间: " + notifyResult.getResult().getUpdateTime());
+
+            // 根据状态处理业务逻辑
+            switch (notifyResult.getResult().getState()) {
+                case "SUCCESS":
+                    System.out.println("转账成功，进行业务处理...");
+                    // 更新订单状态、发送通知等
+                    break;
+                case "FAIL":
+                    System.out.println("转账失败，失败原因: " + notifyResult.getResult().getFailReason());
+                    // 处理失败逻辑
+                    break;
+                default:
+                    System.out.println("其他状态: " + notifyResult.getResult().getState());
+            }
+
+        } catch (WxPayException e) {
+            System.err.println("回调处理失败: " + e.getMessage());
+        }
+    }
+
+    /**
+     * 批量转账示例（使用传统API）
+     * 注意：新商户可能无法使用此API，建议使用新版单笔转账API
+     */
+    public void batchTransferExample() {
+        try {
+            // 构建转账明细列表
+            TransferBatchesRequest.TransferDetail detail1 = TransferBatchesRequest.TransferDetail.newBuilder()
+                .outDetailNo("DETAIL_" + System.currentTimeMillis() + "_1")
+                .transferAmount(100)  // 1元
+                .transferRemark("佣金1")
+                .openid("oUpF8uMuAJO_M2pxb1Q9zNjWeS6o")
+                .userName("张三")
+                .build();
+
+            TransferBatchesRequest.TransferDetail detail2 = TransferBatchesRequest.TransferDetail.newBuilder()
+                .outDetailNo("DETAIL_" + System.currentTimeMillis() + "_2")
+                .transferAmount(200)  // 2元
+                .transferRemark("佣金2")
+                .openid("oUpF8uMuAJO_M2pxb1Q9zNjWeS6p")
+                .userName("李四")
+                .build();
+
+            // 构建批量转账请求
+            TransferBatchesRequest batchRequest = TransferBatchesRequest.newBuilder()
+                .appid("wx1234567890123456")
+                .outBatchNo("BATCH_" + System.currentTimeMillis())
+                .batchName("佣金批量发放")
+                .batchRemark("2024年1月佣金")
+                .totalAmount(300)  // 总金额：3元
+                .totalNum(2)       // 总笔数：2笔
+                .transferDetailList(java.util.Arrays.asList(detail1, detail2))
+                .transferSceneId("1005")  // 转账场景ID
+                .build();
+
+            // 发起批量转账
+            TransferBatchesResult batchResult = transferService.transferBatches(batchRequest);
+
+            System.out.println("=== 批量转账发起成功 ===");
+            System.out.println("商户批次单号: " + batchResult.getOutBatchNo());
+            System.out.println("微信批次单号: " + batchResult.getBatchId());
+            System.out.println("批次状态: " + batchResult.getBatchStatus());
+
+        } catch (WxPayException e) {
+            System.err.println("批量转账失败: " + e.getMessage());
+        }
+    }
+
+    /**
+     * 使用配置示例
+     */
+    public static void main(String[] args) {
+        // 配置微信支付参数
+        WxPayConfig config = new WxPayConfig();
+        config.setAppId("wx1234567890123456");          // 应用ID
+        config.setMchId("1234567890");                  // 商户ID
+        config.setApiV3Key("your_api_v3_key_32_chars"); // APIv3密钥
+        config.setPrivateKeyPath("path/to/private.pem"); // 商户私钥文件路径
+        config.setCertSerialNo("your_certificate_serial"); // 商户证书序列号
+
+        // 创建示例实例
+        NewTransferApiExample example = new NewTransferApiExample(config);
+
+        // 运行示例
+        System.out.println("新版商户转账API使用示例");
+        System.out.println("===============================");
+
+        // 1. 发起单笔转账
+        example.transferExample();
+
+        // 2. 查询转账结果
+        // example.queryByOutBillNoExample();
+
+        // 3. 撤销转账
+        // example.cancelTransferExample();
+
+        // 4. 批量转账（传统API）
+        // example.batchTransferExample();
+    }
+}
\ No newline at end of file
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/exception/WxSignTestException.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/exception/WxSignTestException.java
new file mode 100644
index 0000000000..97a0182adb
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/exception/WxSignTestException.java
@@ -0,0 +1,31 @@
+package com.github.binarywang.wxpay.exception;
+
+/**
+ * <pre>
+ *   微信支付签名探测异常类
+ * </pre>
+ * @author je45
+ * @date 2024/11/27 9:35
+ */
+public class WxSignTestException extends WxPayException {
+  private static final long serialVersionUID = -303371909244098058L;
+
+  /**
+   * Instantiates a new Wx pay exception.
+   *
+   * @param customErrorMsg the custom error msg
+   */
+  public WxSignTestException(String customErrorMsg) {
+    super(customErrorMsg);
+  }
+
+  /**
+   * Instantiates a new Wx pay exception.
+   *
+   * @param customErrorMsg the custom error msg
+   * @param tr             the tr
+   */
+  public WxSignTestException(String customErrorMsg, Throwable tr) {
+    super(customErrorMsg, tr);
+  }
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/ComplaintService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/ComplaintService.java
index 8e86692cd6..6fc1367cf4 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/ComplaintService.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/ComplaintService.java
@@ -135,10 +135,24 @@ public interface ComplaintService {
    */
   void complete(CompleteRequest request) throws WxPayException;
 
+  /**
+   * <pre>
+   * 更新退款审批结果API
+   * 针对“申请退款单”，需要商户明确返回是否可退款的审批结果。
+   * 若根据用户描述，核实可以退款，审批动作传入“APPROVE”，同意退款，并给出一个预计退款时间。传入“同意退款”后，需要额外调退款接口发起原路退款。退款到账后，投诉单的状态将自动扭转为“处理完成”。
+   * 若根据用户描述，核实不能退款，审批动作传入“REJECT”，拒绝退款，并说明拒绝退款原因。驳回退款后，投诉单的状态将自动扭转为“处理完成”。
+   * 文档详见: <a href="https://pay.wechatpay.cn/docs/merchant/apis/consumer-complaint/complaints/update-refund-progress.html">...</a>
+   * </pre>
+   *
+   * @param request {@link UpdateRefundProgressRequest} 请求数据
+   * @throws WxPayException the wx pay exception
+   */
+  void updateRefundProgress(UpdateRefundProgressRequest request) throws WxPayException;
+
   /**
    * <pre>
    * 商户上传反馈图片API
-   * 文档详见: <a href="https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter10_2_10.shtml">...</a>
+   * 文档详见: <a href="https://pay.weixin.qq.com/docs/merchant/apis/consumer-complaint/images/create-images.html">...</a>
    * 接口链接：https://api.mch.weixin.qq.com/v3/merchant-service/images/upload
    * </pre>
    *
@@ -151,7 +165,7 @@ public interface ComplaintService {
   /**
    * <pre>
    * 商户上传反馈图片API
-   * 文档详见: <a href="https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter10_2_10.shtml">...</a>
+   * 文档详见: <a href="https://pay.weixin.qq.com/docs/merchant/apis/consumer-complaint/images/create-images.html">...</a>
    * 接口链接：https://api.mch.weixin.qq.com/v3/merchant-service/images/upload
    * </pre>
    *
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EcommerceService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EcommerceService.java
index 99d17e0732..2dbb2906c3 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EcommerceService.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/EcommerceService.java
@@ -364,6 +364,33 @@ public interface EcommerceService {
    */
   RefundQueryResult queryRefundByRefundId(String subMchid, String refundId) throws WxPayException;
 
+
+  /**
+   * <pre>
+   * 垫付退款回补API
+   * 文档地址: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_6_4.shtml
+   * </pre>
+   *
+   * @param subMchid 二级商户号
+   * @param refundId 微信退款单号
+   * @return 返回数据 return refunds result
+   * @throws WxPayException the wx pay exception
+   */
+  ReturnAdvanceResult refundsReturnAdvance(String subMchid, String refundId) throws WxPayException;
+
+
+  /**
+   * <pre>
+   * 查询垫付回补结果API
+   * 文档地址: https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_6_5.shtml
+   * </pre>
+   *
+   * @param subMchid 二级商户号
+   * @param refundId 微信退款单号
+   * @return 返回数据 return refunds result
+   * @throws WxPayException the wx pay exception
+   */
+  ReturnAdvanceResult queryRefundsReturnAdvance(String subMchid, String refundId) throws WxPayException;
   /**
    * <pre>
    * 查询退款API
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/TransferService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/TransferService.java
index ebf746214d..01113c9506 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/TransferService.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/TransferService.java
@@ -111,4 +111,82 @@ public interface TransferService {
    */
   TransferBatchDetailResult transferBatchesOutBatchNoDetail(String outBatchNo, String outDetailNo) throws WxPayException;
 
+  /**
+   * <pre>
+   *
+   * 2025.1.15 开始新接口 发起商家转账API
+   *
+   * 请求方式：POST（HTTPS）
+   * 请求地址：<a href="https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills">请求地址</a>
+   *
+   * 文档地址：<a href="https://pay.weixin.qq.com/doc/v3/merchant/4012716434">发起商家转账API</a>
+   * </pre>
+   *
+   * @param request 转账请求参数
+   * @return TransferBillsResult 转账结果
+   * @throws WxPayException .
+   */
+  TransferBillsResult transferBills(TransferBillsRequest request) throws WxPayException;
+
+  /**
+   * <pre>
+   *
+   * 2025.1.15 开始新接口 撤销转账API
+   *
+   * 请求方式：POST（HTTPS）
+   * 请求地址：<a href="https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/{out_bill_no}/cancel">请求地址</a>
+   *
+   * 文档地址：<a href="https://pay.weixin.qq.com/doc/v3/merchant/4012716458">商户撤销转账API</a>
+   * </pre>
+   *
+   * @param outBillNo 【商户单号】 商户系统内部的商家单号，要求此参数只能由数字、大小写字母组成，在商户系统内部唯一
+   * @return TransformBillsGetResult 转账单
+   * @throws WxPayException .
+   */
+  TransferBillsCancelResult transformBillsCancel(String outBillNo) throws WxPayException;
+
+  /**
+   * <pre>
+   *
+   * 2025.1.15 开始新接口 发起商家转账API
+   *
+   * 请求方式：GET（HTTPS）
+   * 请求地址：<a href="https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/{out_bill_no}">请求地址</a>
+   *
+   * 文档地址：<a href="https://pay.weixin.qq.com/doc/v3/merchant/4012716437">商户单号查询转账单API</a>
+   * </pre>
+   *
+   * @param outBillNo 【商户单号】 商户系统内部的商家单号，要求此参数只能由数字、大小写字母组成，在商户系统内部唯一
+   * @return TransformBillsGetResult 转账单
+   * @throws WxPayException .
+   */
+  TransferBillsGetResult getBillsByOutBillNo(String outBillNo) throws WxPayException;
+
+  /**
+   * <pre>
+   *
+   * 2025.1.15 开始新接口 微信单号查询转账单API
+   *
+   * 请求方式：GET（HTTPS）
+   * 请求地址：<a href="https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills/transfer-bill-no/{transfer_bill_no}">请求地址</a>
+   *
+   * 文档地址：<a href="https://pay.weixin.qq.com/doc/v3/merchant/4012716437">商户单号查询转账单API</a>
+   * </pre>
+   *
+   * @param transferBillNo 【微信转账单号】 微信转账单号，微信商家转账系统返回的唯一标识
+   * @return TransformBillsGetResult 转账单
+   * @throws WxPayException .
+   */
+  TransferBillsGetResult getBillsByTransferBillNo(String transferBillNo) throws WxPayException;
+
+  /**
+   * 2025.1.15 开始新接口 解析商家转账结果
+   * 详见<a href="https://pay.weixin.qq.com/doc/v3/merchant/4012712115"></a>
+   *
+   * @param notifyData 通知数据
+   * @param header     通知头部数据，不传则表示不校验头
+   * @return the wx transfer notify result
+   * @throws WxPayException the wx pay exception
+   */
+  TransferBillsNotifyResult parseTransferBillsNotifyResult(String notifyData, SignatureHeader header) throws WxPayException;
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxEntrustPapService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxEntrustPapService.java
index 168e43696a..1a1ddb120a 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxEntrustPapService.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxEntrustPapService.java
@@ -166,4 +166,22 @@ public interface WxEntrustPapService {
    * @throws WxPayException the wx pay exception
    */
   WxWithholdOrderQueryResult papOrderQuery(WxWithholdOrderQueryRequest wxWithholdOrderQueryRequest) throws WxPayException;
+
+  /**
+   * <pre>
+   *   签约、解约结果通知解析
+   *   详见：<a href="https://pay.weixin.qq.com/doc/v2/merchant/4011987586">签约、解约结果通知</a>
+   *   注意：
+   *    1、同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。 推荐的做法是：当商户系统收到通知进行处理时，先检查对应业务数据的状态，并判断该通知是否已经处理。如果未处理，则再进行处理；如果已处理，则直接返回结果成功。在对业务数据进行状态检查和处理之前，要采用数据锁进行并发控制，以避免函数重入造成的数据混乱。
+   *    2、如果在所有通知频率(0/10/10/10/30/30/30/300/300/300/300/300/300/300/300/300/300/300/300/300/300/300/300/300/300/300/300/300/300/300（单位：秒）)后没有收到微信侧回调,商户应调用查询订单接口确认订单状态。
+   *   特别提醒：
+   *    1、商户系统对于签约、解约结果通知的内容一定要做签名验证,并校验返回的商户协议号和用户openid信息是否一致，防止数据泄露导致出现“假通知”，造成损失。
+   *    2、当收到通知进行处理时，首先检查对应业务数据的状态，判断该通知是否已经处理过，如果没有处理过再进行处理，如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前，要采用数据锁进行并发控制，以避免函数重入造成的数据混乱。
+   * </pre>
+   *
+   * @param xmlData the wx withhold order query request
+   * @return wx sign result
+   * @throws WxPayException the wx pay exception
+   */
+  WxSignQueryResult parseSignNotifyResult(String xmlData) throws WxPayException;
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java
index 57c2937c62..8ceac2b6ba 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java
@@ -6,6 +6,7 @@
 import com.github.binarywang.wxpay.bean.request.*;
 import com.github.binarywang.wxpay.bean.result.*;
 import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
+import com.github.binarywang.wxpay.bean.transfer.TransferBillsNotifyResult;
 import com.github.binarywang.wxpay.config.WxPayConfig;
 import com.github.binarywang.wxpay.constant.WxPayConstants;
 import com.github.binarywang.wxpay.exception.WxPayException;
@@ -38,16 +39,18 @@ public interface WxPayService {
    * Map里 加入新的 {@link WxPayConfig}，适用于动态添加新的微信商户配置.
    *
    * @param mchId       商户id
+   * @param appId       微信应用id
    * @param wxPayConfig 新的微信配置
    */
-  void addConfig(String mchId, WxPayConfig wxPayConfig);
+  void addConfig(String mchId, String appId, WxPayConfig wxPayConfig);
 
   /**
-   * 从 Map中 移除 {@link String mchId} 所对应的 {@link WxPayConfig}，适用于动态移除微信商户配置.
+   * 从 Map中 移除 {@link String mchId} 和 {@link String appId} 所对应的 {@link WxPayConfig}，适用于动态移除微信商户配置.
    *
    * @param mchId 对应商户的标识
+   * @param appId 微信应用id
    */
-  void removeConfig(String mchId);
+  void removeConfig(String mchId, String appId);
 
   /**
    * 注入多个 {@link WxPayConfig} 的实现. 并为每个 {@link WxPayConfig} 赋予不同的 {@link String mchId} 值
@@ -69,17 +72,19 @@ public interface WxPayService {
    * 进行相应的商户切换.
    *
    * @param mchId 商户标识
+   * @param appId 微信应用id
    * @return 切换是否成功 boolean
    */
-  boolean switchover(String mchId);
+  boolean switchover(String mchId, String appId);
 
   /**
    * 进行相应的商户切换.
    *
    * @param mchId 商户标识
+   * @param appId 微信应用id
    * @return 切换成功 ，则返回当前对象，方便链式调用，否则抛出异常
    */
-  WxPayService switchoverTo(String mchId);
+  WxPayService switchoverTo(String mchId, String appId);
 
   /**
    * 发送post请求，得到响应字节数组.
@@ -616,10 +621,10 @@ public interface WxPayService {
   /**
    * 调用统一下单接口，并组装生成支付所需参数对象.
    *
-   * @param <T>       请使用{@link com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result}里的内部类或字段
+   * @param <T>       请使用{@link WxPayUnifiedOrderV3Result}里的内部类或字段
    * @param tradeType the trade type
    * @param request   统一下单请求参数
-   * @return 返回 {@link com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result}里的内部类或字段
+   * @return 返回 {@link WxPayUnifiedOrderV3Result}里的内部类或字段
    * @throws WxPayException the wx pay exception
    */
   <T> T createOrderV3(TradeTypeEnum tradeType, WxPayUnifiedOrderV3Request request) throws WxPayException;
@@ -627,10 +632,10 @@ public interface WxPayService {
   /**
    * 服务商模式调用统一下单接口，并组装生成支付所需参数对象.
    *
-   * @param <T>       请使用{@link com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result}里的内部类或字段
+   * @param <T>       请使用{@link WxPayUnifiedOrderV3Result}里的内部类或字段
    * @param tradeType the trade type
    * @param request   统一下单请求参数
-   * @return 返回 {@link com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result}里的内部类或字段
+   * @return 返回 {@link WxPayUnifiedOrderV3Result}里的内部类或字段
    * @throws WxPayException the wx pay exception
    */
   <T> T createPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException;
@@ -991,6 +996,17 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
    */
   WxPayTransferBatchesNotifyV3Result parseTransferBatchesNotifyV3Result(String notifyData, SignatureHeader header) throws WxPayException;
 
+  /**
+   * 解析商家转账批次回调通知
+   * https://pay.weixin.qq.com/doc/v3/merchant/4012712115
+   *
+   * @param notifyData
+   * @param header
+   * @return
+   * @throws WxPayException
+   */
+  TransferBillsNotifyResult parseTransferBillsNotifyV3Result(String notifyData, SignatureHeader header) throws WxPayException;
+
   /**
    * 解析服务商模式退款结果通知
    * 详见https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_1_11.shtml
@@ -1603,7 +1619,8 @@ WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, Stri
 
   /**
    * 获取服务商直股份签约计划服务类
-   * @return  the partner pay score sign plan service
+   *
+   * @return the partner pay score sign plan service
    */
   PartnerPayScoreSignPlanService getPartnerPayScoreSignPlanService();
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
index 851040dd13..5057ef2b6b 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
@@ -11,12 +11,13 @@
 import com.github.binarywang.wxpay.bean.request.*;
 import com.github.binarywang.wxpay.bean.result.*;
 import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
+import com.github.binarywang.wxpay.bean.transfer.TransferBillsNotifyResult;
 import com.github.binarywang.wxpay.config.WxPayConfig;
 import com.github.binarywang.wxpay.config.WxPayConfigHolder;
-import com.github.binarywang.wxpay.constant.WxPayConstants;
 import com.github.binarywang.wxpay.constant.WxPayConstants.SignType;
 import com.github.binarywang.wxpay.constant.WxPayConstants.TradeType;
 import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.exception.WxSignTestException;
 import com.github.binarywang.wxpay.service.*;
 import com.github.binarywang.wxpay.util.SignUtils;
 import com.github.binarywang.wxpay.util.XmlConfig;
@@ -29,11 +30,10 @@
 import com.google.gson.GsonBuilder;
 import lombok.Getter;
 import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.error.WxRuntimeException;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.reflect.ConstructorUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.io.File;
 import java.io.IOException;
@@ -44,6 +44,7 @@
 import java.nio.file.Paths;
 import java.security.GeneralSecurityException;
 import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.zip.ZipException;
 
 import static com.github.binarywang.wxpay.constant.WxPayConstants.QUERY_COMMENT_DATE_FORMAT;
@@ -57,14 +58,13 @@
  *
  * @author <a href="https://github.com/binarywang">Binary Wang</a>
  */
+@Slf4j
 public abstract class BaseWxPayServiceImpl implements WxPayService {
   private static final String TOTAL_FUND_COUNT = "资金流水总笔数";
 
   private static final Gson GSON = new GsonBuilder().create();
 
-  final Logger log = LoggerFactory.getLogger(this.getClass());
-
-  static ThreadLocal<WxPayApiData> wxApiData = new ThreadLocal<>();
+  static final ThreadLocal<WxPayApiData> wxApiData = new ThreadLocal<>();
 
 
   @Setter
@@ -120,7 +120,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
   private final PartnerPayScoreService partnerPayScoreService = new PartnerPayScoreServiceImpl(this);
 
   @Getter
-  private final PartnerPayScoreSignPlanService partnerPayScoreSignPlanService=new PartnerPayScoreSignPlanServiceImpl(this);
+  private final PartnerPayScoreSignPlanService partnerPayScoreSignPlanService = new PartnerPayScoreSignPlanServiceImpl(this);
 
   @Getter
   private final MerchantTransferService merchantTransferService = new MerchantTransferServiceImpl(this);
@@ -128,7 +128,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
   @Getter
   private final BrandMerchantTransferService brandMerchantTransferService = new BrandMerchantTransferServiceImpl(this);
 
-  protected Map<String, WxPayConfig> configMap = new HashMap<>();
+  protected Map<String, WxPayConfig> configMap = new ConcurrentHashMap<>();
 
   @Override
   public WxPayConfig getConfig() {
@@ -141,38 +141,37 @@ public WxPayConfig getConfig() {
 
   @Override
   public void setConfig(WxPayConfig config) {
-    final String defaultMchId = config.getMchId();
-    this.setMultiConfig(ImmutableMap.of(defaultMchId, config), defaultMchId);
+    final String defaultKey = this.getConfigKey(config.getMchId(), config.getAppId());
+    this.setMultiConfig(ImmutableMap.of(defaultKey, config), defaultKey);
   }
 
   @Override
-  public void addConfig(String mchId, WxPayConfig wxPayConfig) {
+  public void addConfig(String mchId, String appId, WxPayConfig wxPayConfig) {
     synchronized (this) {
       if (this.configMap == null) {
         this.setConfig(wxPayConfig);
       } else {
-        WxPayConfigHolder.set(mchId);
-        this.configMap.put(mchId, wxPayConfig);
+        String configKey = this.getConfigKey(mchId, appId);
+        WxPayConfigHolder.set(configKey);
+        this.configMap.put(configKey, wxPayConfig);
       }
     }
   }
 
   @Override
-  public void removeConfig(String mchId) {
+  public void removeConfig(String mchId, String appId) {
     synchronized (this) {
-      if (this.configMap.size() == 1) {
-        this.configMap.remove(mchId);
-        log.warn("已删除最后一个商户号配置：{}，须立即使用setConfig或setMultiConfig添加配置", mchId);
+      String configKey = this.getConfigKey(mchId, appId);
+      this.configMap.remove(configKey);
+      if (this.configMap.isEmpty()) {
+        log.warn("已删除最后一个商户号配置：mchId[{}],appid[{}]，须立即使用setConfig或setMultiConfig添加配置", mchId, appId);
         return;
       }
-      if (WxPayConfigHolder.get().equals(mchId)) {
-        this.configMap.remove(mchId);
-        final String defaultMpId = this.configMap.keySet().iterator().next();
-        WxPayConfigHolder.set(defaultMpId);
-        log.warn("已删除默认商户号配置，商户号【{}】被设为默认配置", defaultMpId);
-        return;
+      if (WxPayConfigHolder.get().equals(configKey)) {
+        final String nextConfigKey = this.configMap.keySet().iterator().next();
+        WxPayConfigHolder.set(nextConfigKey);
+        log.warn("已删除默认商户号配置，商户号【{}】被设为默认配置", nextConfigKey);
       }
-      this.configMap.remove(mchId);
     }
   }
 
@@ -182,28 +181,34 @@ public void setMultiConfig(Map<String, WxPayConfig> wxPayConfigs) {
   }
 
   @Override
-  public void setMultiConfig(Map<String, WxPayConfig> wxPayConfigs, String defaultMchId) {
+  public void setMultiConfig(Map<String, WxPayConfig> wxPayConfigs, String defaultConfigKey) {
     this.configMap = Maps.newHashMap(wxPayConfigs);
-    WxPayConfigHolder.set(defaultMchId);
+    WxPayConfigHolder.set(defaultConfigKey);
   }
 
   @Override
-  public boolean switchover(String mchId) {
-    if (this.configMap.containsKey(mchId)) {
-      WxPayConfigHolder.set(mchId);
+  public boolean switchover(String mchId, String appId) {
+    String configKey = this.getConfigKey(mchId, appId);
+    if (this.configMap.containsKey(configKey)) {
+      WxPayConfigHolder.set(configKey);
       return true;
     }
-    log.error("无法找到对应【{}】的商户号配置信息，请核实！", mchId);
+    log.error("无法找到对应mchId=【{}】,appId=【{}】的商户号配置信息，请核实！", mchId, appId);
     return false;
   }
 
   @Override
-  public WxPayService switchoverTo(String mchId) {
-    if (this.configMap.containsKey(mchId)) {
-      WxPayConfigHolder.set(mchId);
+  public WxPayService switchoverTo(String mchId, String appId) {
+    String configKey = this.getConfigKey(mchId, appId);
+    if (this.configMap.containsKey(configKey)) {
+      WxPayConfigHolder.set(configKey);
       return this;
     }
-    throw new WxRuntimeException(String.format("无法找到对应【%s】的商户号配置信息，请核实！", mchId));
+    throw new WxRuntimeException(String.format("无法找到对应mchId=【%s】,appId=【%s】的商户号配置信息，请核实！", mchId, appId));
+  }
+
+  public String getConfigKey(String mchId, String appId) {
+    return mchId + "_" + appId;
   }
 
   @Override
@@ -244,7 +249,7 @@ public WxPayRefundResult refundV2(WxPayRefundRequest request) throws WxPayExcept
   @Override
   public WxPayRefundV3Result refundV3(WxPayRefundV3Request request) throws WxPayException {
     String url = String.format("%s/v3/refund/domestic/refunds", this.getPayBaseUrl());
-    String response = this.postV3(url, GSON.toJson(request));
+    String response = this.postV3WithWechatpaySerial(url, GSON.toJson(request));
     return GSON.fromJson(response, WxPayRefundV3Result.class);
   }
 
@@ -287,21 +292,21 @@ public WxPayRefundQueryResult refundQueryV2(WxPayRefundQueryRequest request) thr
   @Override
   public WxPayRefundQueryV3Result refundQueryV3(String outRefundNo) throws WxPayException {
     String url = String.format("%s/v3/refund/domestic/refunds/%s", this.getPayBaseUrl(), outRefundNo);
-    String response = this.getV3(url);
+    String response = this.getV3WithWechatPaySerial(url);
     return GSON.fromJson(response, WxPayRefundQueryV3Result.class);
   }
 
   @Override
   public WxPayRefundQueryV3Result refundQueryV3(WxPayRefundQueryV3Request request) throws WxPayException {
     String url = String.format("%s/v3/refund/domestic/refunds/%s", this.getPayBaseUrl(), request.getOutRefundNo());
-    String response = this.getV3(url);
+    String response = this.getV3WithWechatPaySerial(url);
     return GSON.fromJson(response, WxPayRefundQueryV3Result.class);
   }
 
   @Override
   public WxPayRefundQueryV3Result refundPartnerQueryV3(WxPayRefundQueryV3Request request) throws WxPayException {
-    String url = String.format("%s/v3/refund/domestic/refunds/%s?sub_mchid=%s", this.getPayBaseUrl(), request.getOutRefundNo(),request.getSubMchid());
-    String response = this.getV3(url);
+    String url = String.format("%s/v3/refund/domestic/refunds/%s?sub_mchid=%s", this.getPayBaseUrl(), request.getOutRefundNo(), request.getSubMchid());
+    String response = this.getV3WithWechatPaySerial(url);
     return GSON.fromJson(response, WxPayRefundQueryV3Result.class);
   }
 
@@ -316,13 +321,13 @@ public WxPayOrderNotifyResult parseOrderNotifyResult(String xmlData, String sign
       log.debug("微信支付异步通知请求参数：{}", xmlData);
       WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlData);
       if (signType == null) {
+        this.switchover(result.getMchId(), result.getAppid());
         if (result.getSignType() != null) {
           // 如果解析的通知对象中signType有值，则使用它进行验签
           signType = result.getSignType();
-        } else if (configMap.get(result.getMchId()).getSignType() != null) {
+        } else if (this.getConfig().getSignType() != null) {
           // 如果配置中signType有值，则使用它进行验签
-          signType = configMap.get(result.getMchId()).getSignType();
-          this.switchover(result.getMchId());
+          signType = this.getConfig().getSignType();
         }
       }
 
@@ -343,7 +348,11 @@ public WxPayOrderNotifyResult parseOrderNotifyResult(String xmlData, String sign
    * @param data   通知数据
    * @return true:校验通过 false:校验不通过
    */
-  private boolean verifyNotifySign(SignatureHeader header, String data) {
+  private boolean verifyNotifySign(SignatureHeader header, String data) throws WxSignTestException {
+    String wxPaySign = header.getSignature();
+    if (wxPaySign.startsWith("WECHATPAY/SIGNTEST/")) {
+      throw new WxSignTestException("微信支付签名探测流量");
+    }
     String beforeSign = String.format("%s\n%s\n%s\n",
       header.getTimeStamp(),
       header.getNonce(),
@@ -415,7 +424,7 @@ public WxPayRefundNotifyResult parseRefundNotifyResult(String xmlData) throws Wx
       WxPayRefundNotifyResult result;
       if (XmlConfig.fastMode) {
         result = BaseWxPayResult.fromXML(xmlData, WxPayRefundNotifyResult.class);
-        this.switchover(result.getMchId());
+        this.switchover(result.getMchId(), result.getAppid());
         result.decryptReqInfo(this.getConfig().getMchKey());
       } else {
         result = WxPayRefundNotifyResult.fromXML(xmlData, this.getConfig().getMchKey());
@@ -437,6 +446,11 @@ public WxPayTransferBatchesNotifyV3Result parseTransferBatchesNotifyV3Result(Str
     return this.baseParseOrderNotifyV3Result(notifyData, header, WxPayTransferBatchesNotifyV3Result.class, WxPayTransferBatchesNotifyV3Result.DecryptNotifyResult.class);
   }
 
+  @Override
+  public TransferBillsNotifyResult parseTransferBillsNotifyV3Result(String notifyData, SignatureHeader header) throws WxPayException {
+    return this.baseParseOrderNotifyV3Result(notifyData, header, TransferBillsNotifyResult.class, TransferBillsNotifyResult.DecryptNotifyResult.class);
+  }
+
   @Override
   public WxPayPartnerRefundNotifyV3Result parsePartnerRefundNotifyV3Result(String notifyData, SignatureHeader header) throws WxPayException {
     return this.baseParseOrderNotifyV3Result(notifyData, header, WxPayPartnerRefundNotifyV3Result.class, WxPayPartnerRefundNotifyV3Result.DecryptNotifyResult.class);
@@ -447,7 +461,7 @@ public WxScanPayNotifyResult parseScanPayNotifyResult(String xmlData, @Deprecate
     try {
       log.debug("扫码支付回调通知请求参数：{}", xmlData);
       WxScanPayNotifyResult result = BaseWxPayResult.fromXML(xmlData, WxScanPayNotifyResult.class);
-      this.switchover(result.getMchId());
+      this.switchover(result.getMchId(), result.getAppid());
       log.debug("扫码支付回调通知解析后的对象：{}", result);
       result.checkResult(this, this.getConfig().getSignType(), false);
       return result;
@@ -507,7 +521,7 @@ public WxPayOrderQueryV3Result queryOrderV3(WxPayOrderQueryV3Request request) th
       url = String.format("%s/v3/pay/transactions/id/%s", this.getPayBaseUrl(), request.getTransactionId());
     }
     String query = String.format("?mchid=%s", request.getMchid());
-    String response = this.getV3(url + query);
+    String response = this.getV3WithWechatPaySerial(url + query);
     return GSON.fromJson(response, WxPayOrderQueryV3Result.class);
   }
 
@@ -532,14 +546,14 @@ public WxPayPartnerOrderQueryV3Result queryPartnerOrderV3(WxPayPartnerOrderQuery
       url = String.format("%s/v3/pay/partner/transactions/id/%s", this.getPayBaseUrl(), request.getTransactionId());
     }
     String query = String.format("?sp_mchid=%s&sub_mchid=%s", request.getSpMchId(), request.getSubMchId());
-    String response = this.getV3(url + query);
+    String response = this.getV3WithWechatPaySerial(url + query);
     return GSON.fromJson(response, WxPayPartnerOrderQueryV3Result.class);
   }
 
   @Override
   public CombineQueryResult queryCombine(String combineOutTradeNo) throws WxPayException {
     String url = String.format("%s/v3/combine-transactions/out-trade-no/%s", this.getPayBaseUrl(), combineOutTradeNo);
-    String response = this.getV3(url);
+    String response = this.getV3WithWechatPaySerial(url);
     return GSON.fromJson(response, CombineQueryResult.class);
   }
 
@@ -593,7 +607,7 @@ public void closeOrderV3(WxPayOrderCloseV3Request request) throws WxPayException
       request.setMchid(this.getConfig().getMchId());
     }
     String url = String.format("%s/v3/pay/transactions/out-trade-no/%s/close", this.getPayBaseUrl(), request.getOutTradeNo());
-    this.postV3(url, GSON.toJson(request));
+    this.postV3WithWechatpaySerial(url, GSON.toJson(request));
   }
 
   @Override
@@ -605,13 +619,13 @@ public void closePartnerOrderV3(WxPayPartnerOrderCloseV3Request request) throws
       request.setSubMchId(this.getConfig().getSubMchId());
     }
     String url = String.format("%s/v3/pay/partner/transactions/out-trade-no/%s/close", this.getPayBaseUrl(), request.getOutTradeNo());
-    this.postV3(url, GSON.toJson(request));
+    this.postV3WithWechatpaySerial(url, GSON.toJson(request));
   }
 
   @Override
   public void closeCombine(CombineCloseRequest request) throws WxPayException {
     String url = String.format("%s/v3/combine-transactions/out-trade-no/%s/close", this.getPayBaseUrl(), request.getCombineOutTradeNo());
-    this.postV3(url, GSON.toJson(request));
+    this.postV3WithWechatpaySerial(url, GSON.toJson(request));
   }
 
   @Override
@@ -755,7 +769,7 @@ public WxPayUnifiedOrderV3Result unifiedPartnerOrderV3(TradeTypeEnum tradeType,
     }
 
     String url = this.getPayBaseUrl() + tradeType.getBasePartnerUrl();
-    String response = this.postV3(url, GSON.toJson(request));
+    String response = this.postV3WithWechatpaySerial(url, GSON.toJson(request));
     return GSON.fromJson(response, WxPayUnifiedOrderV3Result.class);
   }
 
@@ -772,7 +786,7 @@ public WxPayUnifiedOrderV3Result unifiedOrderV3(TradeTypeEnum tradeType, WxPayUn
     }
 
     String url = this.getPayBaseUrl() + tradeType.getPartnerUrl();
-    String response = this.postV3(url, GSON.toJson(request));
+    String response = this.postV3WithWechatpaySerial(url, GSON.toJson(request));
     return GSON.fromJson(response, WxPayUnifiedOrderV3Result.class);
   }
 
@@ -785,14 +799,14 @@ public CombineTransactionsResult combine(TradeTypeEnum tradeType, CombineTransac
       request.setCombineMchid(this.getConfig().getMchId());
     }
     String url = this.getPayBaseUrl() + tradeType.getCombineUrl();
-    String response = this.postV3(url, GSON.toJson(request));
+    String response = this.postV3WithWechatpaySerial(url, GSON.toJson(request));
     return GSON.fromJson(response, CombineTransactionsResult.class);
   }
 
   @Override
   public <T> T combineTransactions(TradeTypeEnum tradeType, CombineTransactionsRequest request) throws WxPayException {
     CombineTransactionsResult result = this.combine(tradeType, request);
-    return result.getPayInfo(tradeType, request.getCombineAppid(), request.getCombineAppid(), this.getConfig().getPrivateKey());
+    return result.getPayInfo(tradeType, request.getCombineAppid(), request.getCombineMchid(), this.getConfig().getPrivateKey());
   }
 
   @Override
@@ -1098,7 +1112,7 @@ public WxPayApplyBillV3Result applyTradeBill(WxPayApplyTradeBillV3Request reques
     } else {
       url = String.format("%s/v3/bill/tradebill?bill_date=%s&bill_type=%s&tar_type=%s", this.getPayBaseUrl(), request.getBillDate(), request.getBillType(), request.getTarType());
     }
-    String response = this.getV3(url);
+    String response = this.getV3WithWechatPaySerial(url);
     return GSON.fromJson(response, WxPayApplyBillV3Result.class);
   }
 
@@ -1110,7 +1124,7 @@ public WxPayApplyBillV3Result applyFundFlowBill(WxPayApplyFundFlowBillV3Request
     } else {
       url = String.format("%s/v3/bill/fundflowbill?bill_date=%s&account_type=%s&tar_type=%s", this.getPayBaseUrl(), request.getBillDate(), request.getAccountType(), request.getTarType());
     }
-    String response = this.getV3(url);
+    String response = this.getV3WithWechatPaySerial(url);
     return GSON.fromJson(response, WxPayApplyBillV3Result.class);
   }
 
@@ -1139,7 +1153,7 @@ public WxPayCodepayResult codepay(WxPayCodepayRequest request) throws WxPayExcep
       request.setMchid(this.getConfig().getMchId());
     }
     String url = String.format("%s/v3/pay/transactions/codepay", this.getPayBaseUrl());
-    String body = this.postV3(url, GSON.toJson(request));
+    String body = this.postV3WithWechatpaySerial(url, GSON.toJson(request));
     return GSON.fromJson(body, WxPayCodepayResult.class);
   }
 
@@ -1165,7 +1179,7 @@ public WxPayOrderReverseV3Result reverseOrderV3(WxPayOrderReverseV3Request reque
     }
     // 拼接参数请求路径并发送
     String url = String.format("%s/v3/pay/transactions/out-trade-no/%s/reverse", this.getPayBaseUrl(), request.getOutTradeNo());
-    String response = this.postV3(url, GSON.toJson(request));
+    String response = this.postV3WithWechatpaySerial(url, GSON.toJson(request));
     return GSON.fromJson(response, WxPayOrderReverseV3Result.class);
   }
 
@@ -1295,7 +1309,7 @@ public String queryComment(WxPayQueryCommentRequest request) throws WxPayExcepti
   @Override
   public WxPayFaceAuthInfoResult getWxPayFaceAuthInfo(WxPayFaceAuthInfoRequest request) throws WxPayException {
     if (StringUtils.isEmpty(request.getSignType())) {
-      request.setSignType(WxPayConstants.SignType.MD5);
+      request.setSignType(SignType.MD5);
     }
 
     request.checkAndSign(this.getConfig());
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BrandMerchantTransferServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BrandMerchantTransferServiceImpl.java
index a9ee5d236d..dff607922b 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BrandMerchantTransferServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BrandMerchantTransferServiceImpl.java
@@ -44,7 +44,7 @@ public BrandBatchesQueryResult queryBrandWxBatches(BrandWxBatchesQueryRequest re
     if (request.getNeedQueryDetail() != null) {
       url = String.format("%s?need_query_detail=%b", url, request.getNeedQueryDetail());
     }
-    if (request.getDetailState() != null && request.getDetailState().length() != 0) {
+    if (request.getDetailState() != null && !request.getDetailState().isEmpty()) {
       url = String.format("%s&detail_state=%s", url, request.getDetailState());
     }
 
@@ -68,7 +68,7 @@ public BrandBatchesQueryResult queryBrandMerchantBatches(BrandMerchantBatchesQue
     if (request.getNeedQueryDetail() != null) {
       url = String.format("%s?need_query_detail=%b", url, request.getNeedQueryDetail());
     }
-    if (request.getDetailState() != null && request.getDetailState().length() != 0) {
+    if (request.getDetailState() != null && !request.getDetailState().isEmpty()) {
       url = String.format("%s&detail_state=%s", url, request.getDetailState());
     }
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/ComplaintServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/ComplaintServiceImpl.java
index 51d9609c41..32d57e081e 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/ComplaintServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/ComplaintServiceImpl.java
@@ -112,6 +112,14 @@ public void complete(CompleteRequest request) throws WxPayException {
     this.payService.postV3(url, GSON.toJson(request));
   }
 
+  @Override
+  public void updateRefundProgress(UpdateRefundProgressRequest request) throws WxPayException {
+    String url = String.format("%s/v3/merchant-service/complaints-v2/%s/update-refund-progress", this.payService.getPayBaseUrl(), request.getComplaintId());
+    // 上面url已经含有complaintId，这里设置为空，避免在body中再次传递，否则微信会报错
+    request.setComplaintId(null);
+    this.payService.postV3(url, GSON.toJson(request));
+  }
+
   @Override
   public ImageUploadResult uploadResponseImage(File imageFile) throws WxPayException, IOException {
     String url = String.format("%s/v3/merchant-service/images/upload", this.payService.getPayBaseUrl());
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/CustomDeclarationServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/CustomDeclarationServiceImpl.java
index d25ed7c0a2..f596d4cf8c 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/CustomDeclarationServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/CustomDeclarationServiceImpl.java
@@ -4,7 +4,6 @@
 import com.github.binarywang.wxpay.exception.WxPayException;
 import com.github.binarywang.wxpay.service.CustomDeclarationService;
 import com.github.binarywang.wxpay.service.WxPayService;
-import com.github.binarywang.wxpay.v3.util.RsaCryptoUtil;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import lombok.RequiredArgsConstructor;
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EcommerceServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EcommerceServiceImpl.java
index 3671ab72ba..479520d7f7 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EcommerceServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/EcommerceServiceImpl.java
@@ -290,6 +290,25 @@ public RefundQueryResult queryRefundByRefundId(String subMchid, String refundId)
     return GSON.fromJson(response, RefundQueryResult.class);
   }
 
+
+  @Override
+  public ReturnAdvanceResult refundsReturnAdvance(String subMchid, String refundId) throws WxPayException {
+    String url = String.format("%s/v3/ecommerce/refunds/%s/return-advance", this.payService.getPayBaseUrl(), refundId);
+    Map<String, String> request = new HashMap<>();
+    request.put("sub_mchid",subMchid);
+    String response = this.payService.postV3(url, GSON.toJson(request));
+    return GSON.fromJson(response, ReturnAdvanceResult.class);
+  }
+
+
+  @Override
+  public ReturnAdvanceResult queryRefundsReturnAdvance(String subMchid, String refundId) throws WxPayException {
+    String url = String.format("%s/v3/ecommerce/refunds/%s/return-advance?sub_mchid=%s", this.payService.getPayBaseUrl(), refundId,subMchid);
+    String response = this.payService.getV3(url);
+    return GSON.fromJson(response, ReturnAdvanceResult.class);
+  }
+
+
   @Override
   public RefundQueryResult queryRefundByOutRefundNo(String subMchid, String outRefundNo) throws WxPayException {
     String url = String.format("%s/v3/ecommerce/refunds/out-refund-no/%s?sub_mchid=%s", this.payService.getPayBaseUrl(), outRefundNo, subMchid);
@@ -470,7 +489,7 @@ private String parseURLPair(Object o) {
   public static Map<Object, Object> getObjectToMap(Object obj) {
     try {
       Map<Object, Object> result = new LinkedHashMap<>();
-      final Class<? extends Object> beanClass = obj.getClass();
+      final Class<?> beanClass = obj.getClass();
       final BeanInfo beanInfo = Introspector.getBeanInfo(beanClass);
       final PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
       if (propertyDescriptors != null) {
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MarketingFavorServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MarketingFavorServiceImpl.java
index a10bbbb085..0f84d5f126 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MarketingFavorServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MarketingFavorServiceImpl.java
@@ -34,7 +34,9 @@ public FavorStocksCreateResult createFavorStocksV3(FavorStocksCreateRequest requ
     String url = String.format("%s/v3/marketing/favor/coupon-stocks", this.payService.getPayBaseUrl());
     RsaCryptoUtil.encryptFields(request, this.payService.getConfig().getVerifier().getValidCertificate());
     String result = this.payService.postV3WithWechatpaySerial(url, GSON.toJson(request));
-    return GSON.fromJson(result, FavorStocksCreateResult.class);
+    FavorStocksCreateResult favorStocksCreateResult = GSON.fromJson(result, FavorStocksCreateResult.class);
+    favorStocksCreateResult.setRawJsonString(result);
+    return favorStocksCreateResult;
   }
 
   @Override
@@ -75,7 +77,9 @@ public FavorStocksGetResult getFavorStocksV3(String stockId, String stockCreator
     String url = String.format("%s/v3/marketing/favor/stocks/%s", this.payService.getPayBaseUrl(), stockId);
     String query = String.format("?stock_creator_mchid=%s", stockCreatorMchid);
     String result = this.payService.getV3(url + query);
-    return GSON.fromJson(result, FavorStocksGetResult.class);
+    FavorStocksGetResult favorStocksGetResult = GSON.fromJson(result, FavorStocksGetResult.class);
+    favorStocksGetResult.setRawJsonString(result);
+    return favorStocksGetResult;
   }
 
   @Override
@@ -83,7 +87,9 @@ public FavorCouponsGetResult getFavorCouponsV3(String couponId, String appid, St
     String url = String.format("%s/v3/marketing/favor/users/%s/coupons/%s", this.payService.getPayBaseUrl(), openid, couponId);
     String query = String.format("?appid=%s", appid);
     String result = this.payService.getV3(url + query);
-    return GSON.fromJson(result, FavorCouponsGetResult.class);
+    FavorCouponsGetResult favorCouponsGetResult = GSON.fromJson(result, FavorCouponsGetResult.class);
+    favorCouponsGetResult.setRawJsonString(result);
+    return favorCouponsGetResult;
   }
 
   @Override
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MerchantTransferServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MerchantTransferServiceImpl.java
index 8c4568a0f8..8974ca7e2b 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MerchantTransferServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/MerchantTransferServiceImpl.java
@@ -47,7 +47,7 @@ public BatchesQueryResult queryWxBatches(WxBatchesQueryRequest request) throws W
     if (request.getLimit() != null) {
       url = String.format("%s&limit=%d", url, request.getLimit());
     }
-    if (request.getDetailStatus() != null && request.getDetailStatus().length() != 0) {
+    if (request.getDetailStatus() != null && !request.getDetailStatus().isEmpty()) {
       url = String.format("%s&detail_status=%s", url, request.getDetailStatus());
     }
 
@@ -74,7 +74,7 @@ public BatchesQueryResult queryMerchantBatches(MerchantBatchesQueryRequest reque
     if (request.getLimit() != null) {
       url = String.format("%s&limit=%d", url, request.getLimit());
     }
-    if (request.getDetailStatus() != null && request.getDetailStatus().length() != 0) {
+    if (request.getDetailStatus() != null && !request.getDetailStatus().isEmpty()) {
       url = String.format("%s&detail_status=%s", url, request.getDetailStatus());
     }
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/PayScoreServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/PayScoreServiceImpl.java
index ed36bd7f08..249cfa3f56 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/PayScoreServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/PayScoreServiceImpl.java
@@ -7,6 +7,7 @@
 import com.github.binarywang.wxpay.bean.payscore.WxPayScoreResult;
 import com.github.binarywang.wxpay.config.WxPayConfig;
 import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.exception.WxSignTestException;
 import com.github.binarywang.wxpay.service.PayScoreService;
 import com.github.binarywang.wxpay.service.WxPayService;
 import com.github.binarywang.wxpay.v3.util.AesUtils;
@@ -327,7 +328,11 @@ public WxPayScoreResult decryptNotifyDataResource(PayScoreNotifyData data) throw
    * @param data   通知数据
    * @return true:校验通过 false:校验不通过
    */
-  private boolean verifyNotifySign(SignatureHeader header, String data) {
+  private boolean verifyNotifySign(SignatureHeader header, String data) throws WxSignTestException {
+    String wxPaySign = header.getSigned();
+    if(wxPaySign.startsWith("WECHATPAY/SIGNTEST/")){
+      throw new WxSignTestException("微信支付签名探测流量");
+    }
     String beforeSign = String.format("%s\n%s\n%s\n", header.getTimeStamp(), header.getNonce(), data);
     return payService.getConfig().getVerifier().verify(header.getSerialNo(),
       beforeSign.getBytes(StandardCharsets.UTF_8), header.getSigned());
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/TransferServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/TransferServiceImpl.java
index e62dc9c053..038af32b87 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/TransferServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/TransferServiceImpl.java
@@ -48,8 +48,7 @@ public QueryTransferBatchesResult transferBatchesBatchId(QueryTransferBatchesReq
     if (request.getNeedQueryDetail()) {
       url = String.format("%s/v3/transfer/batches/batch-id/%s?need_query_detail=true&offset=%s&limit=%s&detail_status=%s",
         this.payService.getPayBaseUrl(), request.getBatchId(), request.getOffset(), request.getLimit(), request.getDetailStatus());
-    }
-    else {
+    } else {
       url = String.format("%s/v3/transfer/batches/batch-id/%s?need_query_detail=false",
         this.payService.getPayBaseUrl(), request.getBatchId());
     }
@@ -70,8 +69,7 @@ public QueryTransferBatchesResult transferBatchesOutBatchNo(QueryTransferBatches
     if (request.getNeedQueryDetail()) {
       url = String.format("%s/v3/transfer/batches/out-batch-no/%s?need_query_detail=true&offset=%s&limit=%s&detail_status=%s",
         this.payService.getPayBaseUrl(), request.getOutBatchNo(), request.getOffset(), request.getLimit(), request.getDetailStatus());
-    }
-    else {
+    } else {
       url = String.format("%s/v3/transfer/batches/out-batch-no/%s?need_query_detail=false",
         this.payService.getPayBaseUrl(), request.getOutBatchNo());
     }
@@ -85,4 +83,45 @@ public TransferBatchDetailResult transferBatchesOutBatchNoDetail(String outBatch
     String result = this.payService.getV3(url);
     return GSON.fromJson(result, TransferBatchDetailResult.class);
   }
+
+  @Override
+  public TransferBillsResult transferBills(TransferBillsRequest request) throws WxPayException {
+    String url = String.format("%s/v3/fund-app/mch-transfer/transfer-bills", this.payService.getPayBaseUrl());
+    if (request.getUserName() != null && !request.getUserName().isEmpty()) {
+      X509Certificate validCertificate = this.payService.getConfig().getVerifier().getValidCertificate();
+      RsaCryptoUtil.encryptFields(request, validCertificate);
+    }
+    String result = this.payService.postV3WithWechatpaySerial(url, GSON.toJson(request));
+    return GSON.fromJson(result, TransferBillsResult.class);
+  }
+
+  @Override
+  public TransferBillsCancelResult transformBillsCancel(String outBillNo) throws WxPayException {
+    String url = String.format("%s/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/%s/cancel",
+      this.payService.getPayBaseUrl(), outBillNo);
+    String result = this.payService.postV3(url, "");
+
+    return GSON.fromJson(result, TransferBillsCancelResult.class);
+  }
+
+  @Override
+  public TransferBillsGetResult getBillsByOutBillNo(String outBillNo) throws WxPayException {
+    String url = String.format("%s/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/%s",
+      this.payService.getPayBaseUrl(), outBillNo);
+    String result = this.payService.getV3(url);
+    return GSON.fromJson(result, TransferBillsGetResult.class);
+  }
+
+  @Override
+  public TransferBillsGetResult getBillsByTransferBillNo(String transferBillNo) throws WxPayException {
+    String url = String.format("%s/v3/fund-app/mch-transfer/transfer-bills/transfer-bill-no/%s",
+      this.payService.getPayBaseUrl(), transferBillNo);
+    String result = this.payService.getV3(url);
+    return GSON.fromJson(result, TransferBillsGetResult.class);
+  }
+
+  @Override
+  public TransferBillsNotifyResult parseTransferBillsNotifyResult(String notifyData, SignatureHeader header) throws WxPayException {
+    return this.payService.baseParseOrderNotifyV3Result(notifyData, header, TransferBillsNotifyResult.class, TransferBillsNotifyResult.DecryptNotifyResult.class);
+  }
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxEntrustPapServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxEntrustPapServiceImpl.java
index 951c1d5a8c..b70a7dee37 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxEntrustPapServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxEntrustPapServiceImpl.java
@@ -10,6 +10,7 @@
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.util.json.WxGsonBuilder;
+import org.apache.commons.lang3.StringUtils;
 
 import java.net.URLEncoder;
 
@@ -65,8 +66,13 @@ public WxH5EntrustResult h5Sign(WxH5EntrustRequest wxH5EntrustRequest) throws Wx
     strBuilder.append("&contract_code=").append(wxH5EntrustRequest.getContractCode());
     strBuilder.append("&contract_display_account=").append(URLEncoder.encode(wxH5EntrustRequest.getContractDisplayAccount()));
     strBuilder.append("&mch_id=").append(wxH5EntrustRequest.getMchId()).append("&notify_url=").append(URLEncoder.encode(wxH5EntrustRequest.getNotifyUrl()));
-    strBuilder.append("&plan_id=").append(wxH5EntrustRequest.getPlanId()).append("&outerid=").append(URLEncoder.encode(wxH5EntrustRequest.getOuterId()));
-    strBuilder.append("&return_appid=").append(wxH5EntrustRequest.getReturnAppid());
+    strBuilder.append("&plan_id=").append(wxH5EntrustRequest.getPlanId());
+    if (StringUtils.isNotEmpty(wxH5EntrustRequest.getOuterId())) {
+      strBuilder.append("&outerid=").append(URLEncoder.encode(wxH5EntrustRequest.getOuterId()));
+    }
+    if (StringUtils.isNotEmpty(wxH5EntrustRequest.getReturnAppid())) {
+      strBuilder.append("&return_appid=").append(wxH5EntrustRequest.getReturnAppid());
+    }
     strBuilder.append("&clientip=").append(wxH5EntrustRequest.getClientIp());
     strBuilder.append("&request_serial=").append(wxH5EntrustRequest.getRequestSerial()).append("&timestamp=").append(wxH5EntrustRequest.getTimestamp());
     strBuilder.append("&version=").append(wxH5EntrustRequest.getVersion()).append("&sign=").append(sign);
@@ -148,4 +154,11 @@ public WxWithholdOrderQueryResult papOrderQuery(WxWithholdOrderQueryRequest wxWi
     wxWithholdOrderQueryResult.checkResult(payService, wxWithholdOrderQueryRequest.getSignType(), true);
     return wxWithholdOrderQueryResult;
   }
+
+  @Override
+  public WxSignQueryResult parseSignNotifyResult(String xmlData) throws WxPayException {
+    WxSignQueryResult result = BaseWxPayResult.fromXML(xmlData, WxSignQueryResult.class);
+    result.checkResult(payService, WxPayConstants.SignType.MD5, true);
+    return result;
+  }
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java
index e2b6d43fa1..977a2856fe 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImpl.java
@@ -1,10 +1,13 @@
 package com.github.binarywang.wxpay.service.impl;
 
 import com.github.binarywang.wxpay.bean.WxPayApiData;
+import com.github.binarywang.wxpay.config.WxPayConfig;
 import com.github.binarywang.wxpay.exception.WxPayException;
 import com.github.binarywang.wxpay.v3.WxPayV3DownloadHttpGet;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.util.http.apache.ByteArrayResponseHandler;
 import me.chanjar.weixin.common.util.json.GsonParser;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.http.*;
@@ -38,30 +41,28 @@
  *
  * @author <a href="https://github.com/binarywang">Binary Wang</a>
  */
+@Slf4j
 public class WxPayServiceApacheHttpImpl extends BaseWxPayServiceImpl {
 
   private static final String ACCEPT = "Accept";
   private static final String CONTENT_TYPE = "Content-Type";
   private static final String APPLICATION_JSON = "application/json";
+  private static final String WECHAT_PAY_SERIAL = "Wechatpay-Serial";
 
   @Override
   public byte[] postForBytes(String url, String requestStr, boolean useKey) throws WxPayException {
     try {
-      HttpClientBuilder httpClientBuilder = createHttpClientBuilder(useKey);
       HttpPost httpPost = this.createHttpPost(url, requestStr);
-      try (CloseableHttpClient httpClient = httpClientBuilder.build()) {
-        try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
-          final byte[] bytes = EntityUtils.toByteArray(response.getEntity());
-          final String responseData = Base64.getEncoder().encodeToString(bytes);
-          this.log.info("\n【请求地址】：{}\n【请求数据】：{}\n【响应数据(Base64编码后)】：{}", url, requestStr, responseData);
-          wxApiData.set(new WxPayApiData(url, requestStr, responseData, null));
-          return bytes;
-        }
-      } finally {
-        httpPost.releaseConnection();
-      }
+      CloseableHttpClient httpClient = this.createHttpClient(useKey);
+      
+      // 使用连接池的客户端，不需要手动关闭
+      final byte[] bytes = httpClient.execute(httpPost, ByteArrayResponseHandler.INSTANCE);
+      final String responseData = Base64.getEncoder().encodeToString(bytes);
+      this.logRequestAndResponse(url, requestStr, responseData);
+      wxApiData.set(new WxPayApiData(url, requestStr, responseData, null));
+      return bytes;
     } catch (Exception e) {
-      this.log.error("\n【请求地址】：{}\n【请求数据】：{}\n【异常信息】：{}", url, requestStr, e.getMessage());
+      this.logError(url, requestStr, e);
       wxApiData.set(new WxPayApiData(url, requestStr, null, e.getMessage()));
       throw new WxPayException(e.getMessage(), e);
     }
@@ -70,22 +71,22 @@ public byte[] postForBytes(String url, String requestStr, boolean useKey) throws
   @Override
   public String post(String url, String requestStr, boolean useKey) throws WxPayException {
     try {
-      HttpClientBuilder httpClientBuilder = this.createHttpClientBuilder(useKey);
       HttpPost httpPost = this.createHttpPost(url, requestStr);
-      try (CloseableHttpClient httpClient = httpClientBuilder.build()) {
-        try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
-          String responseString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
-          this.log.info("\n【请求地址】：{}\n【请求数据】：{}\n【响应数据】：{}", url, requestStr, responseString);
-          if (this.getConfig().isIfSaveApiData()) {
-            wxApiData.set(new WxPayApiData(url, requestStr, responseString, null));
-          }
-          return responseString;
+      CloseableHttpClient httpClient = this.createHttpClient(useKey);
+      
+      // 使用连接池的客户端，不需要手动关闭
+      try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
+        String responseString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
+        this.logRequestAndResponse(url, requestStr, responseString);
+        if (this.getConfig().isIfSaveApiData()) {
+          wxApiData.set(new WxPayApiData(url, requestStr, responseString, null));
         }
+        return responseString;
       } finally {
         httpPost.releaseConnection();
       }
     } catch (Exception e) {
-      this.log.error("\n【请求地址】：{}\n【请求数据】：{}\n【异常信息】：{}", url, requestStr, e.getMessage());
+      this.logError(url, requestStr, e);
       if (this.getConfig().isIfSaveApiData()) {
         wxApiData.set(new WxPayApiData(url, requestStr, null, e.getMessage()));
       }
@@ -95,11 +96,14 @@ public String post(String url, String requestStr, boolean useKey) throws WxPayEx
 
   @Override
   public String postV3(String url, String requestStr) throws WxPayException {
-    CloseableHttpClient httpClient = this.createApiV3HttpClient();
     HttpPost httpPost = this.createHttpPost(url, requestStr);
-    httpPost.addHeader(ACCEPT, APPLICATION_JSON);
-    httpPost.addHeader(CONTENT_TYPE, APPLICATION_JSON);
-    try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
+    this.configureRequest(httpPost);
+    return this.requestV3(url, requestStr, httpPost);
+  }
+
+  private String requestV3(String url, String requestStr, HttpRequestBase httpRequestBase) throws WxPayException {
+    CloseableHttpClient httpClient = this.createApiV3HttpClient();
+    try (CloseableHttpResponse response = httpClient.execute(httpRequestBase)) {
       //v3已经改为通过状态码判断200 204 成功
       int statusCode = response.getStatusLine().getStatusCode();
       //post方法有可能会没有返回值的情况
@@ -109,7 +113,7 @@ public String postV3(String url, String requestStr) throws WxPayException {
       }
 
       if (HttpStatus.SC_OK == statusCode || HttpStatus.SC_NO_CONTENT == statusCode) {
-        this.log.info("\n【请求地址】：{}\n【请求数据】：{}\n【响应数据】：{}", url, requestStr, responseString);
+        this.logRequestAndResponse(url, requestStr, responseString);
         return responseString;
       }
 
@@ -117,62 +121,25 @@ public String postV3(String url, String requestStr) throws WxPayException {
       JsonObject jsonObject = GsonParser.parse(responseString);
       throw convertException(jsonObject);
     } catch (Exception e) {
-      this.log.error("\n【请求地址】：{}\n【请求数据】：{}\n【异常信息】：{}", url, requestStr, e.getMessage());
+      this.logError(url, requestStr, e);
       throw (e instanceof WxPayException) ? (WxPayException) e : new WxPayException(e.getMessage(), e);
     } finally {
-      httpPost.releaseConnection();
+      httpRequestBase.releaseConnection();
     }
-
-
   }
 
   @Override
   public String patchV3(String url, String requestStr) throws WxPayException {
-    CloseableHttpClient httpClient = this.createApiV3HttpClient();
     HttpPatch httpPatch = new HttpPatch(url);
-    httpPatch.setEntity(this.createEntry(requestStr));
-
-    httpPatch.setConfig(RequestConfig.custom()
-      .setConnectionRequestTimeout(this.getConfig().getHttpConnectionTimeout())
-      .setConnectTimeout(this.getConfig().getHttpConnectionTimeout())
-      .setSocketTimeout(this.getConfig().getHttpTimeout())
-      .build());
-
-    httpPatch.addHeader(ACCEPT, APPLICATION_JSON);
-    httpPatch.addHeader(CONTENT_TYPE, APPLICATION_JSON);
-    try (CloseableHttpResponse response = httpClient.execute(httpPatch)) {
-      //v3已经改为通过状态码判断200 204 成功
-      int statusCode = response.getStatusLine().getStatusCode();
-      //post方法有可能会没有返回值的情况
-      String responseString = null;
-      if (response.getEntity() != null) {
-        responseString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
-      }
-
-      if (HttpStatus.SC_OK == statusCode || HttpStatus.SC_NO_CONTENT == statusCode) {
-        this.log.info("\n【请求地址】：{}\n【请求数据】：{}\n【响应数据】：{}", url, requestStr, responseString);
-        return responseString;
-      }
-
-      //有错误提示信息返回
-      JsonObject jsonObject = GsonParser.parse(responseString);
-      throw convertException(jsonObject);
-    } catch (Exception e) {
-      this.log.error("\n【请求地址】：{}\n【请求数据】：{}\n【异常信息】：{}", url, requestStr, e.getMessage());
-      throw (e instanceof WxPayException) ? (WxPayException) e : new WxPayException(e.getMessage(), e);
-    } finally {
-      httpPatch.releaseConnection();
-    }
+    httpPatch.setEntity(createEntry(requestStr));
+    return this.requestV3(url, requestStr, httpPatch);
   }
 
   @Override
   public String postV3WithWechatpaySerial(String url, String requestStr) throws WxPayException {
-    CloseableHttpClient httpClient = this.createApiV3HttpClient();
     HttpPost httpPost = this.createHttpPost(url, requestStr);
-    httpPost.addHeader(ACCEPT, APPLICATION_JSON);
-    httpPost.addHeader(CONTENT_TYPE, APPLICATION_JSON);
-    String serialNumber = getConfig().getVerifier().getValidCertificate().getSerialNumber().toString(16).toUpperCase();
-    httpPost.addHeader("Wechatpay-Serial", serialNumber);
+    this.configureRequest(httpPost);
+    CloseableHttpClient httpClient = this.createApiV3HttpClient();
     try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
       //v3已经改为通过状态码判断200 204 成功
       int statusCode = response.getStatusLine().getStatusCode();
@@ -183,7 +150,7 @@ public String postV3WithWechatpaySerial(String url, String requestStr) throws Wx
       }
 
       if (HttpStatus.SC_OK == statusCode || HttpStatus.SC_NO_CONTENT == statusCode) {
-        this.log.info("\n【请求地址】：{}\n【请求数据】：{}\n【响应数据】：{}", url, requestStr, responseString);
+        this.logRequestAndResponse(url, requestStr, responseString);
         return responseString;
       }
 
@@ -191,8 +158,7 @@ public String postV3WithWechatpaySerial(String url, String requestStr) throws Wx
       JsonObject jsonObject = GsonParser.parse(responseString);
       throw convertException(jsonObject);
     } catch (Exception e) {
-      this.log.error("\n【请求地址】：{}\n【请求数据】：{}\n【异常信息】：{}", url, requestStr, e.getMessage());
-      e.printStackTrace();
+      this.logError(url, requestStr, e);
       throw (e instanceof WxPayException) ? (WxPayException) e : new WxPayException(e.getMessage(), e);
     } finally {
       httpPost.releaseConnection();
@@ -206,12 +172,7 @@ public String postV3(String url, HttpPost httpPost) throws WxPayException {
 
   @Override
   public String requestV3(String url, HttpRequestBase httpRequest) throws WxPayException {
-    httpRequest.setConfig(RequestConfig.custom()
-      .setConnectionRequestTimeout(this.getConfig().getHttpConnectionTimeout())
-      .setConnectTimeout(this.getConfig().getHttpConnectionTimeout())
-      .setSocketTimeout(this.getConfig().getHttpTimeout())
-      .build());
-
+    this.configureRequest(httpRequest);
     CloseableHttpClient httpClient = this.createApiV3HttpClient();
     try (CloseableHttpResponse response = httpClient.execute(httpRequest)) {
       //v3已经改为通过状态码判断200 204 成功
@@ -223,7 +184,7 @@ public String requestV3(String url, HttpRequestBase httpRequest) throws WxPayExc
       }
 
       if (HttpStatus.SC_OK == statusCode || HttpStatus.SC_NO_CONTENT == statusCode) {
-        this.log.info("\n【请求地址】：{}\n【响应数据】：{}", url, responseString);
+        log.info("\n【请求地址】：{}\n【响应数据】：{}", url, responseString);
         return responseString;
       }
 
@@ -231,7 +192,7 @@ public String requestV3(String url, HttpRequestBase httpRequest) throws WxPayExc
       JsonObject jsonObject = GsonParser.parse(responseString);
       throw convertException(jsonObject);
     } catch (Exception e) {
-      this.log.error("\n【请求地址】：{}\n【异常信息】：{}", url, e.getMessage());
+      log.error("\n【请求地址】：{}\n【异常信息】：{}", url, e.getMessage());
       throw (e instanceof WxPayException) ? (WxPayException) e : new WxPayException(e.getMessage(), e);
     } finally {
       httpRequest.releaseConnection();
@@ -240,27 +201,24 @@ public String requestV3(String url, HttpRequestBase httpRequest) throws WxPayExc
 
   @Override
   public String getV3(String url) throws WxPayException {
+    if (this.getConfig().isStrictlyNeedWechatPaySerial()) {
+      return getV3WithWechatPaySerial(url);
+    }
     HttpGet httpGet = new HttpGet(url);
-    httpGet.addHeader(ACCEPT, APPLICATION_JSON);
-    httpGet.addHeader(CONTENT_TYPE, APPLICATION_JSON);
     return this.requestV3(url, httpGet);
   }
 
   @Override
   public String getV3WithWechatPaySerial(String url) throws WxPayException {
     HttpGet httpGet = new HttpGet(url);
-    httpGet.addHeader(ACCEPT, APPLICATION_JSON);
-    httpGet.addHeader(CONTENT_TYPE, APPLICATION_JSON);
-    String serialNumber = getConfig().getVerifier().getValidCertificate().getSerialNumber().toString(16).toUpperCase();
-    httpGet.addHeader("Wechatpay-Serial", serialNumber);
     return this.requestV3(url, httpGet);
   }
 
   @Override
   public InputStream downloadV3(String url) throws WxPayException {
-    CloseableHttpClient httpClient = this.createApiV3HttpClient();
     HttpGet httpGet = new WxPayV3DownloadHttpGet(url);
-    httpGet.addHeader(ACCEPT, ContentType.WILDCARD.getMimeType());
+    this.configureRequest(httpGet);
+    CloseableHttpClient httpClient = this.createApiV3HttpClient();
     try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
       //v3已经改为通过状态码判断200 204 成功
       int statusCode = response.getStatusLine().getStatusCode();
@@ -268,7 +226,7 @@ public InputStream downloadV3(String url) throws WxPayException {
       boolean isJsonContentType = Objects.nonNull(contentType) && ContentType.APPLICATION_JSON.getMimeType()
         .equals(ContentType.parse(String.valueOf(contentType.getValue())).getMimeType());
       if ((HttpStatus.SC_OK == statusCode || HttpStatus.SC_NO_CONTENT == statusCode) && !isJsonContentType) {
-        this.log.info("\n【请求地址】：{}\n", url);
+        log.info("\n【请求地址】：{}\n", url);
         return response.getEntity().getContent();
       }
 
@@ -278,7 +236,7 @@ public InputStream downloadV3(String url) throws WxPayException {
       JsonObject jsonObject = GsonParser.parse(responseString);
       throw convertException(jsonObject);
     } catch (Exception e) {
-      this.log.error("\n【请求地址】：{}\n【异常信息】：{}", url, e.getMessage());
+      log.error("\n【请求地址】：{}\n【异常信息】：{}", url, e.getMessage());
       throw (e instanceof WxPayException) ? (WxPayException) e : new WxPayException(e.getMessage(), e);
     } finally {
       httpGet.releaseConnection();
@@ -288,21 +246,33 @@ public InputStream downloadV3(String url) throws WxPayException {
   @Override
   public String putV3(String url, String requestStr) throws WxPayException {
     HttpPut httpPut = new HttpPut(url);
-    StringEntity entity = this.createEntry(requestStr);
+    StringEntity entity = createEntry(requestStr);
     httpPut.setEntity(entity);
-    httpPut.addHeader(ACCEPT, APPLICATION_JSON);
-    httpPut.addHeader(CONTENT_TYPE, APPLICATION_JSON);
     return requestV3(url, httpPut);
   }
 
   @Override
   public String deleteV3(String url) throws WxPayException {
     HttpDelete httpDelete = new HttpDelete(url);
-    httpDelete.addHeader(ACCEPT, APPLICATION_JSON);
-    httpDelete.addHeader(CONTENT_TYPE, APPLICATION_JSON);
     return requestV3(url, httpDelete);
   }
 
+  private void configureRequest(HttpRequestBase request) {
+    String serialNumber = getWechatPaySerial(getConfig());
+    String method = request.getMethod();
+    request.addHeader(ACCEPT, APPLICATION_JSON);
+    if (!method.equals("POST")) {
+      request.addHeader(CONTENT_TYPE, APPLICATION_JSON);
+    }
+    request.addHeader(WECHAT_PAY_SERIAL, serialNumber);
+
+    request.setConfig(RequestConfig.custom()
+      .setConnectionRequestTimeout(this.getConfig().getHttpConnectionTimeout())
+      .setConnectTimeout(this.getConfig().getHttpConnectionTimeout())
+      .setSocketTimeout(this.getConfig().getHttpTimeout())
+      .build());
+  }
+
   private CloseableHttpClient createApiV3HttpClient() throws WxPayException {
     CloseableHttpClient apiV3HttpClient = this.getConfig().getApiV3HttpClient();
     if (null == apiV3HttpClient) {
@@ -311,8 +281,28 @@ private CloseableHttpClient createApiV3HttpClient() throws WxPayException {
     return apiV3HttpClient;
   }
 
-  private StringEntity createEntry(String requestStr) {
-    return new StringEntity(requestStr, ContentType.create(APPLICATION_JSON, "utf-8"));
+  CloseableHttpClient createHttpClient(boolean useKey) throws WxPayException {
+    if (useKey) {
+      // 使用SSL连接池客户端
+      CloseableHttpClient sslHttpClient = this.getConfig().getSslHttpClient();
+      if (null == sslHttpClient) {
+        this.getConfig().initSslHttpClient();
+        sslHttpClient = this.getConfig().getSslHttpClient();
+      }
+      return sslHttpClient;
+    } else {
+      // 使用普通连接池客户端
+      CloseableHttpClient httpClient = this.getConfig().getHttpClient();
+      if (null == httpClient) {
+        this.getConfig().initHttpClient();
+        httpClient = this.getConfig().getHttpClient();
+      }
+      return httpClient;
+    }
+  }
+
+  private static StringEntity createEntry(String requestStr) {
+    return new StringEntity(requestStr, ContentType.create(APPLICATION_JSON, StandardCharsets.UTF_8));
     //return new StringEntity(new String(requestStr.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
   }
 
@@ -347,7 +337,7 @@ private HttpClientBuilder createHttpClientBuilder(boolean useKey) throws WxPayEx
 
   private HttpPost createHttpPost(String url, String requestStr) {
     HttpPost httpPost = new HttpPost(url);
-    httpPost.setEntity(this.createEntry(requestStr));
+    httpPost.setEntity(createEntry(requestStr));
 
     httpPost.setConfig(RequestConfig.custom()
       .setConnectionRequestTimeout(this.getConfig().getHttpConnectionTimeout())
@@ -368,9 +358,8 @@ private void initSSLContext(HttpClientBuilder httpClientBuilder) throws WxPayExc
       new DefaultHostnameVerifier()));
   }
 
-
   private WxPayException convertException(JsonObject jsonObject) {
-    //todo 这里考虑使用新的适用于V3的异常
+    //TODO 这里考虑使用新的适用于V3的异常
     JsonElement codeElement = jsonObject.get("code");
     String code = codeElement == null ? null : codeElement.getAsString();
     String message = jsonObject.get("message").getAsString();
@@ -380,4 +369,22 @@ private WxPayException convertException(JsonObject jsonObject) {
     return wxPayException;
   }
 
+  /**
+   * 兼容微信支付公钥模式
+   */
+  private String getWechatPaySerial(WxPayConfig wxPayConfig) {
+    if (StringUtils.isNotBlank(wxPayConfig.getPublicKeyId())) {
+      return wxPayConfig.getPublicKeyId();
+    }
+
+    return wxPayConfig.getVerifier().getValidCertificate().getSerialNumber().toString(16).toUpperCase();
+  }
+
+  private void logRequestAndResponse(String url, String requestStr, String responseStr) {
+    log.info("\n【请求地址】：{}\n【请求数据】：{}\n【响应数据】：{}", url, requestStr, responseStr);
+  }
+
+  private void logError(String url, String requestStr, Exception e) {
+    log.error("\n【请求地址】：{}\n【请求数据】：{}\n【异常信息】：{}", url, requestStr, e.getMessage());
+  }
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceHttpComponentsImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceHttpComponentsImpl.java
new file mode 100644
index 0000000000..1c558f711b
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceHttpComponentsImpl.java
@@ -0,0 +1,367 @@
+package com.github.binarywang.wxpay.service.impl;
+
+import com.github.binarywang.wxpay.bean.WxPayApiData;
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.v3.WxPayV3DownloadHttpGet;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.util.http.apache.ByteArrayResponseHandler;
+import me.chanjar.weixin.common.util.json.GsonParser;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.*;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.*;
+import org.apache.http.conn.ssl.DefaultHostnameVerifier;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+
+import javax.net.ssl.SSLContext;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * 微信支付请求实现类，apache httpconponents 实现.
+ *
+ * @author altusea
+ */
+@Slf4j
+public class WxPayServiceHttpComponentsImpl extends BaseWxPayServiceImpl {
+
+  private static final String ACCEPT = "Accept";
+  private static final String CONTENT_TYPE = "Content-Type";
+  private static final String APPLICATION_JSON = "application/json";
+  private static final String WECHAT_PAY_SERIAL = "Wechatpay-Serial";
+
+  @Override
+  public byte[] postForBytes(String url, String requestStr, boolean useKey) throws WxPayException {
+    try {
+      HttpClientBuilder httpClientBuilder = createHttpClientBuilder(useKey);
+      HttpPost httpPost = this.createHttpPost(url, requestStr);
+      try (CloseableHttpClient httpClient = httpClientBuilder.build()) {
+        final byte[] bytes = httpClient.execute(httpPost, ByteArrayResponseHandler.INSTANCE);
+        final String responseData = Base64.getEncoder().encodeToString(bytes);
+        this.logRequestAndResponse(url, requestStr, responseData);
+        wxApiData.set(new WxPayApiData(url, requestStr, responseData, null));
+        return bytes;
+      }
+    } catch (Exception e) {
+      this.logError(url, requestStr, e);
+      wxApiData.set(new WxPayApiData(url, requestStr, null, e.getMessage()));
+      throw new WxPayException(e.getMessage(), e);
+    }
+  }
+
+  @Override
+  public String post(String url, String requestStr, boolean useKey) throws WxPayException {
+    try {
+      HttpClientBuilder httpClientBuilder = this.createHttpClientBuilder(useKey);
+      HttpPost httpPost = this.createHttpPost(url, requestStr);
+      try (CloseableHttpClient httpClient = httpClientBuilder.build()) {
+        try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
+          String responseString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
+          this.logRequestAndResponse(url, requestStr, responseString);
+          if (this.getConfig().isIfSaveApiData()) {
+            wxApiData.set(new WxPayApiData(url, requestStr, responseString, null));
+          }
+          return responseString;
+        }
+      } finally {
+        httpPost.releaseConnection();
+      }
+    } catch (Exception e) {
+      this.logError(url, requestStr, e);
+      if (this.getConfig().isIfSaveApiData()) {
+        wxApiData.set(new WxPayApiData(url, requestStr, null, e.getMessage()));
+      }
+      throw new WxPayException(e.getMessage(), e);
+    }
+  }
+
+  @Override
+  public String postV3(String url, String requestStr) throws WxPayException {
+    HttpPost httpPost = this.createHttpPost(url, requestStr);
+    this.configureRequest(httpPost);
+    return this.requestV3(url, requestStr, httpPost);
+  }
+
+  private String requestV3(String url, String requestStr, HttpRequestBase httpRequestBase) throws WxPayException {
+    CloseableHttpClient httpClient = this.createApiV3HttpClient();
+    try (CloseableHttpResponse response = httpClient.execute(httpRequestBase)) {
+      //v3已经改为通过状态码判断200 204 成功
+      int statusCode = response.getStatusLine().getStatusCode();
+      //post方法有可能会没有返回值的情况
+      String responseString = null;
+      if (response.getEntity() != null) {
+        responseString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
+      }
+
+      if (HttpStatus.SC_OK == statusCode || HttpStatus.SC_NO_CONTENT == statusCode) {
+        this.logRequestAndResponse(url, requestStr, responseString);
+        return responseString;
+      }
+
+      //有错误提示信息返回
+      JsonObject jsonObject = GsonParser.parse(responseString);
+      throw convertException(jsonObject);
+    } catch (Exception e) {
+      this.logError(url, requestStr, e);
+      throw (e instanceof WxPayException) ? (WxPayException) e : new WxPayException(e.getMessage(), e);
+    } finally {
+      httpRequestBase.releaseConnection();
+    }
+  }
+
+  @Override
+  public String patchV3(String url, String requestStr) throws WxPayException {
+    HttpPatch httpPatch = new HttpPatch(url);
+    httpPatch.setEntity(createEntry(requestStr));
+    return this.requestV3(url, requestStr, httpPatch);
+  }
+
+  @Override
+  public String postV3WithWechatpaySerial(String url, String requestStr) throws WxPayException {
+    HttpPost httpPost = this.createHttpPost(url, requestStr);
+    this.configureRequest(httpPost);
+    CloseableHttpClient httpClient = this.createApiV3HttpClient();
+    try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
+      //v3已经改为通过状态码判断200 204 成功
+      int statusCode = response.getStatusLine().getStatusCode();
+      String responseString = "{}";
+      HttpEntity entity = response.getEntity();
+      if (entity != null) {
+        responseString = EntityUtils.toString(entity, StandardCharsets.UTF_8);
+      }
+
+      if (HttpStatus.SC_OK == statusCode || HttpStatus.SC_NO_CONTENT == statusCode) {
+        this.logRequestAndResponse(url, requestStr, responseString);
+        return responseString;
+      }
+
+      //有错误提示信息返回
+      JsonObject jsonObject = GsonParser.parse(responseString);
+      throw convertException(jsonObject);
+    } catch (Exception e) {
+      this.logError(url, requestStr, e);
+      throw (e instanceof WxPayException) ? (WxPayException) e : new WxPayException(e.getMessage(), e);
+    } finally {
+      httpPost.releaseConnection();
+    }
+  }
+
+  @Override
+  public String postV3(String url, HttpPost httpPost) throws WxPayException {
+    return this.requestV3(url, httpPost);
+  }
+
+  @Override
+  public String requestV3(String url, HttpRequestBase httpRequest) throws WxPayException {
+    this.configureRequest(httpRequest);
+    CloseableHttpClient httpClient = this.createApiV3HttpClient();
+    try (CloseableHttpResponse response = httpClient.execute(httpRequest)) {
+      //v3已经改为通过状态码判断200 204 成功
+      int statusCode = response.getStatusLine().getStatusCode();
+      //post方法有可能会没有返回值的情况
+      String responseString = null;
+      if (response.getEntity() != null) {
+        responseString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
+      }
+
+      if (HttpStatus.SC_OK == statusCode || HttpStatus.SC_NO_CONTENT == statusCode) {
+        log.info("\n【请求地址】：{}\n【响应数据】：{}", url, responseString);
+        return responseString;
+      }
+
+      //有错误提示信息返回
+      JsonObject jsonObject = GsonParser.parse(responseString);
+      throw convertException(jsonObject);
+    } catch (Exception e) {
+      log.error("\n【请求地址】：{}\n【异常信息】：{}", url, e.getMessage());
+      throw (e instanceof WxPayException) ? (WxPayException) e : new WxPayException(e.getMessage(), e);
+    } finally {
+      httpRequest.releaseConnection();
+    }
+  }
+
+  @Override
+  public String getV3(String url) throws WxPayException {
+    if (this.getConfig().isStrictlyNeedWechatPaySerial()) {
+      return getV3WithWechatPaySerial(url);
+    }
+    HttpGet httpGet = new HttpGet(url);
+    return this.requestV3(url, httpGet);
+  }
+
+  @Override
+  public String getV3WithWechatPaySerial(String url) throws WxPayException {
+    HttpGet httpGet = new HttpGet(url);
+    return this.requestV3(url, httpGet);
+  }
+
+  @Override
+  public InputStream downloadV3(String url) throws WxPayException {
+    HttpGet httpGet = new WxPayV3DownloadHttpGet(url);
+    this.configureRequest(httpGet);
+    CloseableHttpClient httpClient = this.createApiV3HttpClient();
+    try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
+      //v3已经改为通过状态码判断200 204 成功
+      int statusCode = response.getStatusLine().getStatusCode();
+      Header contentType = response.getFirstHeader(HttpHeaders.CONTENT_TYPE);
+      boolean isJsonContentType = Objects.nonNull(contentType) && ContentType.APPLICATION_JSON.getMimeType()
+        .equals(ContentType.parse(String.valueOf(contentType.getValue())).getMimeType());
+      if ((HttpStatus.SC_OK == statusCode || HttpStatus.SC_NO_CONTENT == statusCode) && !isJsonContentType) {
+        log.info("\n【请求地址】：{}\n", url);
+        return response.getEntity().getContent();
+      }
+
+      //response里的header有content-type=json说明返回了错误信息
+      //有错误提示信息返回
+      String responseString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
+      JsonObject jsonObject = GsonParser.parse(responseString);
+      throw convertException(jsonObject);
+    } catch (Exception e) {
+      log.error("\n【请求地址】：{}\n【异常信息】：{}", url, e.getMessage());
+      throw (e instanceof WxPayException) ? (WxPayException) e : new WxPayException(e.getMessage(), e);
+    } finally {
+      httpGet.releaseConnection();
+    }
+  }
+
+  @Override
+  public String putV3(String url, String requestStr) throws WxPayException {
+    HttpPut httpPut = new HttpPut(url);
+    StringEntity entity = createEntry(requestStr);
+    httpPut.setEntity(entity);
+    return requestV3(url, httpPut);
+  }
+
+  @Override
+  public String deleteV3(String url) throws WxPayException {
+    HttpDelete httpDelete = new HttpDelete(url);
+    return requestV3(url, httpDelete);
+  }
+
+  private void configureRequest(HttpRequestBase request) {
+    String serialNumber = getWechatPaySerial(getConfig());
+    String method = request.getMethod();
+    request.addHeader(ACCEPT, APPLICATION_JSON);
+    if (!method.equals("POST")) {
+      request.addHeader(CONTENT_TYPE, APPLICATION_JSON);
+    }
+    request.addHeader(WECHAT_PAY_SERIAL, serialNumber);
+
+    request.setConfig(RequestConfig.custom()
+      .setConnectionRequestTimeout(this.getConfig().getHttpConnectionTimeout())
+      .setConnectTimeout(this.getConfig().getHttpConnectionTimeout())
+      .setSocketTimeout(this.getConfig().getHttpTimeout())
+      .build());
+  }
+
+  private CloseableHttpClient createApiV3HttpClient() throws WxPayException {
+    CloseableHttpClient apiV3HttpClient = this.getConfig().getApiV3HttpClient();
+    if (null == apiV3HttpClient) {
+      return this.getConfig().initApiV3HttpClient();
+    }
+    return apiV3HttpClient;
+  }
+
+  private static StringEntity createEntry(String requestStr) {
+    return new StringEntity(requestStr, ContentType.create(APPLICATION_JSON, StandardCharsets.UTF_8));
+    //return new StringEntity(new String(requestStr.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
+  }
+
+  private HttpClientBuilder createHttpClientBuilder(boolean useKey) throws WxPayException {
+    HttpClientBuilder httpClientBuilder = HttpClients.custom();
+    if (useKey) {
+      this.initSSLContext(httpClientBuilder);
+    }
+
+    if (StringUtils.isNotBlank(this.getConfig().getHttpProxyHost()) && this.getConfig().getHttpProxyPort() > 0) {
+      if (StringUtils.isEmpty(this.getConfig().getHttpProxyUsername())) {
+        this.getConfig().setHttpProxyUsername("whatever");
+      }
+
+      // 使用代理服务器 需要用户认证的代理服务器
+      CredentialsProvider provider = new BasicCredentialsProvider();
+      provider.setCredentials(new AuthScope(this.getConfig().getHttpProxyHost(),
+          this.getConfig().getHttpProxyPort()),
+        new UsernamePasswordCredentials(this.getConfig().getHttpProxyUsername(),
+          this.getConfig().getHttpProxyPassword()));
+      httpClientBuilder.setDefaultCredentialsProvider(provider)
+        .setProxy(new HttpHost(this.getConfig().getHttpProxyHost(), this.getConfig().getHttpProxyPort()));
+    }
+
+    // 提供自定义httpClientBuilder的能力
+    Optional.ofNullable(getConfig().getHttpClientBuilderCustomizer()).ifPresent(e -> {
+      e.customize(httpClientBuilder);
+    });
+
+    return httpClientBuilder;
+  }
+
+  private HttpPost createHttpPost(String url, String requestStr) {
+    HttpPost httpPost = new HttpPost(url);
+    httpPost.setEntity(createEntry(requestStr));
+
+    httpPost.setConfig(RequestConfig.custom()
+      .setConnectionRequestTimeout(this.getConfig().getHttpConnectionTimeout())
+      .setConnectTimeout(this.getConfig().getHttpConnectionTimeout())
+      .setSocketTimeout(this.getConfig().getHttpTimeout())
+      .build());
+
+    return httpPost;
+  }
+
+  private void initSSLContext(HttpClientBuilder httpClientBuilder) throws WxPayException {
+    SSLContext sslContext = this.getConfig().getSslContext();
+    if (null == sslContext) {
+      sslContext = this.getConfig().initSSLContext();
+    }
+
+    httpClientBuilder.setSSLSocketFactory(new SSLConnectionSocketFactory(sslContext,
+      new DefaultHostnameVerifier()));
+  }
+
+  private WxPayException convertException(JsonObject jsonObject) {
+    //TODO 这里考虑使用新的适用于V3的异常
+    JsonElement codeElement = jsonObject.get("code");
+    String code = codeElement == null ? null : codeElement.getAsString();
+    String message = jsonObject.get("message").getAsString();
+    WxPayException wxPayException = new WxPayException(message);
+    wxPayException.setErrCode(code);
+    wxPayException.setErrCodeDes(message);
+    return wxPayException;
+  }
+
+  /**
+   * 兼容微信支付公钥模式
+   */
+  private String getWechatPaySerial(WxPayConfig wxPayConfig) {
+    if (StringUtils.isNotBlank(wxPayConfig.getPublicKeyId())) {
+      return wxPayConfig.getPublicKeyId();
+    }
+
+    return wxPayConfig.getVerifier().getValidCertificate().getSerialNumber().toString(16).toUpperCase();
+  }
+
+  private void logRequestAndResponse(String url, String requestStr, String responseStr) {
+    log.info("\n【请求地址】：{}\n【请求数据】：{}\n【响应数据】：{}", url, requestStr, responseStr);
+  }
+
+  private void logError(String url, String requestStr, Exception e) {
+    log.error("\n【请求地址】：{}\n【请求数据】：{}\n【异常信息】：{}", url, requestStr, e.getMessage());
+  }
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java
index 5e6d23eac9..7c2f1e82c0 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/WxPayServiceJoddHttpImpl.java
@@ -9,6 +9,7 @@
 import jodd.http.ProxyInfo.ProxyType;
 import jodd.http.net.SSLSocketHttpConnectionProvider;
 import jodd.http.net.SocketHttpConnectionProvider;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.methods.HttpRequestBase;
@@ -24,6 +25,7 @@
  *
  * @author <a href="https://github.com/binarywang">Binary Wang</a>
  */
+@Slf4j
 public class WxPayServiceJoddHttpImpl extends BaseWxPayServiceImpl {
   @Override
   public byte[] postForBytes(String url, String requestStr, boolean useKey) throws WxPayException {
@@ -31,13 +33,13 @@ public byte[] postForBytes(String url, String requestStr, boolean useKey) throws
       HttpRequest request = this.buildHttpRequest(url, requestStr, useKey);
       byte[] responseBytes = request.send().bodyBytes();
       final String responseString = Base64.getEncoder().encodeToString(responseBytes);
-      this.log.info("\n【请求地址】：{}\n【请求数据】：{}\n【响应数据(Base64编码后)】：{}", url, requestStr, responseString);
+      log.info("\n【请求地址】：{}\n【请求数据】：{}\n【响应数据(Base64编码后)】：{}", url, requestStr, responseString);
       if (this.getConfig().isIfSaveApiData()) {
         wxApiData.set(new WxPayApiData(url, requestStr, responseString, null));
       }
       return responseBytes;
     } catch (Exception e) {
-      this.log.error("\n【请求地址】：{}\n【请求数据】：{}\n【异常信息】：{}", url, requestStr, e.getMessage());
+      log.error("\n【请求地址】：{}\n【请求数据】：{}\n【异常信息】：{}", url, requestStr, e.getMessage());
       wxApiData.set(new WxPayApiData(url, requestStr, null, e.getMessage()));
       throw new WxPayException(e.getMessage(), e);
     }
@@ -49,13 +51,13 @@ public String post(String url, String requestStr, boolean useKey) throws WxPayEx
       HttpRequest request = this.buildHttpRequest(url, requestStr, useKey);
       String responseString = this.getResponseString(request.send());
 
-      this.log.info("\n【请求地址】：{}\n【请求数据】：{}\n【响应数据】：{}", url, requestStr, responseString);
+      log.info("\n【请求地址】：{}\n【请求数据】：{}\n【响应数据】：{}", url, requestStr, responseString);
       if (this.getConfig().isIfSaveApiData()) {
         wxApiData.set(new WxPayApiData(url, requestStr, responseString, null));
       }
       return responseString;
     } catch (Exception e) {
-      this.log.error("\n【请求地址】：{}\n【请求数据】：{}\n【异常信息】：{}", url, requestStr, e.getMessage());
+      log.error("\n【请求地址】：{}\n【请求数据】：{}\n【异常信息】：{}", url, requestStr, e.getMessage());
       wxApiData.set(new WxPayApiData(url, requestStr, null, e.getMessage()));
       throw new WxPayException(e.getMessage(), e);
     }
@@ -146,9 +148,9 @@ private HttpRequest buildHttpRequest(String url, String requestStr, boolean useK
 
   private String getResponseString(HttpResponse response) throws WxPayException {
     try {
-      this.log.debug("【微信服务器响应头信息】：\n{}", response.toString(false));
+      log.debug("【微信服务器响应头信息】：\n{}", response.toString(false));
     } catch (NullPointerException e) {
-      this.log.warn("HttpResponse.toString() 居然抛出空指针异常了", e);
+      log.warn("HttpResponse.toString() 居然抛出空指针异常了", e);
     }
 
     String responseString = response.bodyText();
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/SignUtils.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/SignUtils.java
index 9e005a813e..6c0009fd18 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/SignUtils.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/SignUtils.java
@@ -92,8 +92,7 @@ public static String createSign(Map<String, String> params, String signType, Str
     for (String key : new TreeMap<>(params).keySet()) {
       String value = params.get(key);
       boolean shouldSign = false;
-      if (StringUtils.isNotEmpty(value) && !ArrayUtils.contains(ignoredParams, key)
-        && !NO_SIGN_PARAMS.contains(key)) {
+      if (StringUtils.isNotEmpty(value) && !ArrayUtils.contains(ignoredParams, key) && !NO_SIGN_PARAMS.contains(key)) {
         shouldSign = true;
       }
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/ZipUtils.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/ZipUtils.java
index f9c434196a..1bab0432e6 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/ZipUtils.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/ZipUtils.java
@@ -24,7 +24,7 @@ public static File unGzip(final File file) throws IOException {
     resultFile.createNewFile();
 
     try (FileOutputStream fos = new FileOutputStream(resultFile);
-         GZIPInputStream gzis = new GZIPInputStream(new FileInputStream(file));) {
+         GZIPInputStream gzis = new GZIPInputStream(new FileInputStream(file))) {
       IOUtils.copy(gzis, fos);
     }
 
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/WxPayV3HttpClientBuilder.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/WxPayV3HttpClientBuilder.java
index f479367239..c88c884f57 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/WxPayV3HttpClientBuilder.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/WxPayV3HttpClientBuilder.java
@@ -2,13 +2,9 @@
 
 
 import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-import java.util.List;
 
-import com.github.binarywang.wxpay.v3.auth.CertificatesVerifier;
 import com.github.binarywang.wxpay.v3.auth.PrivateKeySigner;
 import com.github.binarywang.wxpay.v3.auth.WxPayCredentials;
-import com.github.binarywang.wxpay.v3.auth.WxPayValidator;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClientBuilder;
 import org.apache.http.impl.execchain.ClientExecChain;
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/AutoUpdateCertificatesVerifier.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/AutoUpdateCertificatesVerifier.java
index abcae7dff7..21624d455f 100755
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/AutoUpdateCertificatesVerifier.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/AutoUpdateCertificatesVerifier.java
@@ -135,7 +135,7 @@ private void checkAndAutoUpdateCert() {
           //更新时间
           instant = Instant.now();
         } catch (GeneralSecurityException | IOException e) {
-          log.warn("Auto update cert failed, exception = " + e);
+          log.warn("Auto update cert failed, exception = {}", e);
         } finally {
           lock.unlock();
         }
@@ -169,7 +169,7 @@ private void autoUpdateCert() throws IOException, GeneralSecurityException {
       }
       this.verifier = new CertificatesVerifier(newCertList);
     } else {
-      log.warn("Auto update cert failed, statusCode = " + statusCode + ",body = " + body);
+      log.warn("Auto update cert failed, statusCode = {},body = {}", statusCode, body);
       throw new WxRuntimeException(this.getErrorMsg(body));
     }
   }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/PublicCertificateVerifier.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/PublicCertificateVerifier.java
new file mode 100644
index 0000000000..8c9c4f3569
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/PublicCertificateVerifier.java
@@ -0,0 +1,48 @@
+package com.github.binarywang.wxpay.v3.auth;
+
+import java.security.*;
+import java.security.cert.X509Certificate;
+import java.util.Base64;
+import me.chanjar.weixin.common.error.WxRuntimeException;
+
+public class PublicCertificateVerifier implements Verifier{
+
+    private final PublicKey publicKey;
+
+    private Verifier certificateVerifier;
+
+    private final X509PublicCertificate publicCertificate;
+
+    public PublicCertificateVerifier(PublicKey publicKey, String publicId) {
+        this.publicKey = publicKey;
+        this.publicCertificate = new X509PublicCertificate(publicKey, publicId);
+    }
+
+   public void setOtherVerifier(Verifier verifier) {
+      this.certificateVerifier = verifier;
+   }
+
+    @Override
+    public boolean verify(String serialNumber, byte[] message, String signature) {
+        if (!serialNumber.contains("PUB_KEY_ID") && this.certificateVerifier != null) {
+            return this.certificateVerifier.verify(serialNumber, message, signature);
+        }
+        try {
+            Signature sign = Signature.getInstance("SHA256withRSA");
+            sign.initVerify(publicKey);
+            sign.update(message);
+            return sign.verify(Base64.getDecoder().decode(signature));
+        } catch (NoSuchAlgorithmException e) {
+            throw new WxRuntimeException("当前Java环境不支持SHA256withRSA", e);
+        } catch (SignatureException e) {
+            throw new WxRuntimeException("签名验证过程发生了错误", e);
+        } catch (InvalidKeyException e) {
+            throw new WxRuntimeException("无效的证书", e);
+        }
+    }
+
+    @Override
+    public X509Certificate getValidCertificate() {
+        return this.publicCertificate;
+    }
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/Verifier.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/Verifier.java
index 49f92e2f5b..22676601c0 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/Verifier.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/Verifier.java
@@ -7,4 +7,6 @@ public interface Verifier {
 
 
   X509Certificate getValidCertificate();
+
+  default void setOtherVerifier(Verifier verifier) {};
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/WxPayValidator.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/WxPayValidator.java
index acb75bb6cd..cc88caf758 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/WxPayValidator.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/WxPayValidator.java
@@ -10,6 +10,7 @@
 import org.apache.http.util.EntityUtils;
 
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 
 /**
  * @author spvycf & F00lish
@@ -39,7 +40,7 @@ public final boolean validate(CloseableHttpResponse response) throws IOException
     }
 
     String message = buildMessage(response);
-    return verifier.verify(serialNo.getValue(), message.getBytes("utf-8"), sign.getValue());
+    return verifier.verify(serialNo.getValue(), message.getBytes(StandardCharsets.UTF_8), sign.getValue());
   }
 
   protected final String buildMessage(CloseableHttpResponse response) throws IOException {
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/X509PublicCertificate.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/X509PublicCertificate.java
new file mode 100644
index 0000000000..39d147c6ac
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/X509PublicCertificate.java
@@ -0,0 +1,150 @@
+package com.github.binarywang.wxpay.v3.auth;
+
+import java.math.BigInteger;
+import java.security.*;
+import java.security.cert.*;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Set;
+
+public class X509PublicCertificate extends X509Certificate {
+
+    private final PublicKey publicKey;
+
+    private final String publicId;
+
+    public X509PublicCertificate(PublicKey publicKey, String publicId) {
+        this.publicKey = publicKey;
+        this.publicId = publicId;
+    }
+
+    @Override
+    public PublicKey getPublicKey() {
+        return this.publicKey;
+    }
+
+    @Override
+    public BigInteger getSerialNumber() {
+        return new BigInteger(publicId.replace("PUB_KEY_ID_", ""), 16);
+    }
+
+    @Override
+    public void checkValidity() throws CertificateExpiredException, CertificateNotYetValidException {
+    }
+
+    @Override
+    public void checkValidity(Date date) throws CertificateExpiredException, CertificateNotYetValidException {
+
+    }
+
+    @Override
+    public int getVersion() {
+        return 0;
+    }
+
+    @Override
+    public Principal getIssuerDN() {
+        return null;
+    }
+
+    @Override
+    public Principal getSubjectDN() {
+        return null;
+    }
+
+    @Override
+    public Date getNotBefore() {
+        return null;
+    }
+
+    @Override
+    public Date getNotAfter() {
+        return null;
+    }
+
+    @Override
+    public byte[] getTBSCertificate() throws CertificateEncodingException {
+        return new byte[0];
+    }
+
+    @Override
+    public byte[] getSignature() {
+        return new byte[0];
+    }
+
+    @Override
+    public String getSigAlgName() {
+        return "";
+    }
+
+    @Override
+    public String getSigAlgOID() {
+        return "";
+    }
+
+    @Override
+    public byte[] getSigAlgParams() {
+        return new byte[0];
+    }
+
+    @Override
+    public boolean[] getIssuerUniqueID() {
+        return new boolean[0];
+    }
+
+    @Override
+    public boolean[] getSubjectUniqueID() {
+        return new boolean[0];
+    }
+
+    @Override
+    public boolean[] getKeyUsage() {
+        return new boolean[0];
+    }
+
+    @Override
+    public int getBasicConstraints() {
+        return 0;
+    }
+
+    @Override
+    public byte[] getEncoded() throws CertificateEncodingException {
+        return new byte[0];
+    }
+
+    @Override
+    public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException {
+
+    }
+
+    @Override
+    public void verify(PublicKey key, String sigProvider) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException {
+
+    }
+
+    @Override
+    public String toString() {
+        return "";
+    }
+
+
+    @Override
+    public boolean hasUnsupportedCriticalExtension() {
+        return false;
+    }
+
+    @Override
+    public Set<String> getCriticalExtensionOIDs() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public Set<String> getNonCriticalExtensionOIDs() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public byte[] getExtensionValue(String oid) {
+        return new byte[0];
+    }
+}
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/PemUtils.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/PemUtils.java
index 1983fb3387..a885ea0950 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/PemUtils.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/PemUtils.java
@@ -1,13 +1,12 @@
 package com.github.binarywang.wxpay.v3.util;
 
-import me.chanjar.weixin.common.error.WxRuntimeException;
-
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.security.KeyFactory;
 import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
+import java.security.PublicKey;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateExpiredException;
 import java.security.cert.CertificateFactory;
@@ -15,7 +14,9 @@
 import java.security.cert.X509Certificate;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
 import java.util.Base64;
+import me.chanjar.weixin.common.error.WxRuntimeException;
 
 public class PemUtils {
 
@@ -59,4 +60,28 @@ public static X509Certificate loadCertificate(InputStream inputStream) {
       throw new WxRuntimeException("无效的证书", e);
     }
   }
+
+  public static PublicKey loadPublicKey(InputStream inputStream){
+    try {
+      ByteArrayOutputStream array = new ByteArrayOutputStream();
+      byte[] buffer = new byte[1024];
+      int length;
+      while ((length = inputStream.read(buffer)) != -1) {
+        array.write(buffer, 0, length);
+      }
+
+      String publicKey = array.toString("utf-8")
+        .replace("-----BEGIN PUBLIC KEY-----", "")
+        .replace("-----END PUBLIC KEY-----", "")
+        .replaceAll("\\s+", "");
+      return KeyFactory.getInstance("RSA")
+        .generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey)));
+    } catch (NoSuchAlgorithmException e) {
+      throw new WxRuntimeException("当前Java环境不支持RSA", e);
+    } catch (InvalidKeySpecException e) {
+      throw new WxRuntimeException("无效的密钥格式");
+    } catch (IOException e) {
+      throw new WxRuntimeException("无效的密钥");
+    }
+  }
 }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/RsaCryptoUtil.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/RsaCryptoUtil.java
index d8fe3b35ba..8c3e2ace53 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/RsaCryptoUtil.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/RsaCryptoUtil.java
@@ -47,7 +47,7 @@ private static void encryptField(Object encryptObject, X509Certificate certifica
           Object oldValue = field.get(encryptObject);
           if (oldValue != null) {
             String oldStr = (String) oldValue;
-            if (!"".equals(oldStr.trim())) {
+            if (!oldStr.trim().isEmpty()) {
               field.set(encryptObject, encryptOAEP(oldStr, certificate));
             }
           }
@@ -57,8 +57,8 @@ private static void encryptField(Object encryptObject, X509Certificate certifica
           if (obj == null) {
             continue;
           }
-          if (obj instanceof Collection) {
-            Collection collection = (Collection) obj;
+          if (obj instanceof Collection<?>) {
+            Collection<?> collection = (Collection<?>) obj;
             for (Object o : collection) {
               if (o != null) {
                 encryptField(o, certificate);
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksGetResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksGetResultTest.java
new file mode 100644
index 0000000000..ed39413833
--- /dev/null
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/marketing/FavorStocksGetResultTest.java
@@ -0,0 +1,164 @@
+package com.github.binarywang.wxpay.bean.marketing;
+
+import com.github.binarywang.wxpay.bean.result.BaseWxPayV3Result;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.*;
+
+/**
+ * 测试FavorStocksGetResult的原始JSON保存功能
+ *
+ * @author Binary Wang
+ */
+public class FavorStocksGetResultTest {
+
+  private static final Gson GSON = new GsonBuilder().create();
+
+  @Test
+  public void testRawJsonPreservation() {
+    // 模拟微信API返回的JSON（包含未在Result类中定义的字段）
+    String mockJson = "{\n" +
+      "  \"stock_id\": \"9836588\",\n" +
+      "  \"stock_creator_mchid\": \"1230000109\",\n" +
+      "  \"stock_name\": \"微信支付代金券\",\n" +
+      "  \"status\": \"running\",\n" +
+      "  \"create_time\": \"2021-01-01T00:00:00.000+08:00\",\n" +
+      "  \"description\": \"微信支付营销\",\n" +
+      "  \"card_id\": \"pFS7Fjg9kqcMOBtl3bFn\",\n" +
+      "  \"extra_field\": \"这是一个新增字段\"\n" +
+      "}";
+
+    // 模拟服务调用：反序列化JSON
+    FavorStocksGetResult result = GSON.fromJson(mockJson, FavorStocksGetResult.class);
+    
+    // 模拟服务调用：设置原始JSON
+    result.setRawJsonString(mockJson);
+
+    // 验证基本字段正常解析
+    assertEquals(result.getStockId(), "9836588");
+    assertEquals(result.getStockCreatorMchId(), "1230000109");
+    assertEquals(result.getStockName(), "微信支付代金券");
+    assertEquals(result.getStatus(), "running");
+
+    // 验证原始JSON被保存
+    assertNotNull(result.getRawJsonString());
+    assertEquals(result.getRawJsonString(), mockJson);
+
+    // 验证可以从原始JSON中获取未定义的字段
+    assertTrue(result.getRawJsonString().contains("\"card_id\": \"pFS7Fjg9kqcMOBtl3bFn\""));
+    assertTrue(result.getRawJsonString().contains("\"extra_field\": \"这是一个新增字段\""));
+  }
+
+  @Test
+  public void testBaseV3ResultInheritance() {
+    FavorStocksGetResult result = new FavorStocksGetResult();
+    
+    // 验证继承关系
+    assertTrue(result instanceof BaseWxPayV3Result);
+    
+    // 验证基类方法可用
+    result.setRawJsonString("test json");
+    assertEquals(result.getRawJsonString(), "test json");
+  }
+
+  @Test
+  public void testNullRawJson() {
+    FavorStocksGetResult result = new FavorStocksGetResult();
+    
+    // 验证初始状态下rawJsonString为null
+    assertNull(result.getRawJsonString());
+    
+    // 验证设置null不会出错
+    result.setRawJsonString(null);
+    assertNull(result.getRawJsonString());
+  }
+
+  @Test
+  public void testRealWorldUsagePattern() {
+    // 实际使用场景的示例
+    String realApiResponse = "{\n" +
+      "  \"stock_id\": \"9836588\",\n" +
+      "  \"stock_creator_mchid\": \"1230000109\",\n" +
+      "  \"stock_name\": \"微信支付代金券\",\n" +
+      "  \"status\": \"running\",\n" +
+      "  \"create_time\": \"2021-01-01T00:00:00.000+08:00\",\n" +
+      "  \"description\": \"微信支付营销\",\n" +
+      "  \"card_id\": \"pFS7Fjg9kqcMOBtl3bFn\",\n" +
+      "  \"future_field_1\": \"未来可能新增的字段1\",\n" +
+      "  \"future_field_2\": \"未来可能新增的字段2\"\n" +
+      "}";
+
+    FavorStocksGetResult result = GSON.fromJson(realApiResponse, FavorStocksGetResult.class);
+    result.setRawJsonString(realApiResponse);
+
+    // 1. 正常使用已定义的字段
+    assertEquals(result.getStockId(), "9836588");
+    assertEquals(result.getStockName(), "微信支付代金券");
+
+    // 2. 安全地获取可能存在的新字段
+    String cardId = getStringFieldSafely(result, "card_id");
+    assertEquals(cardId, "pFS7Fjg9kqcMOBtl3bFn");
+
+    // 3. 获取未来可能新增的字段
+    String futureField1 = getStringFieldSafely(result, "future_field_1");
+    assertEquals(futureField1, "未来可能新增的字段1");
+
+    String nonExistentField = getStringFieldSafely(result, "non_existent");
+    assertNull(nonExistentField);
+  }
+
+  @Test
+  public void testCardIdExtractionExample() {
+    // 测试具体的card_id字段提取（这是issue中提到的用例）
+    String apiResponseWithCardId = "{\n" +
+      "  \"stock_id\": \"9836588\",\n" +
+      "  \"stock_creator_mchid\": \"1230000109\",\n" +
+      "  \"stock_name\": \"微信支付代金券\",\n" +
+      "  \"status\": \"running\",\n" +
+      "  \"card_id\": \"pFS7Fjg9kqcMOBtl3bFn\"\n" +
+      "}";
+
+    FavorStocksGetResult result = GSON.fromJson(apiResponseWithCardId, FavorStocksGetResult.class);
+    result.setRawJsonString(apiResponseWithCardId);
+
+    // 验证可以获取card_id字段
+    JsonElement jsonElement = JsonParser.parseString(result.getRawJsonString());
+    assertTrue(jsonElement.getAsJsonObject().has("card_id"));
+    String cardId = jsonElement.getAsJsonObject().get("card_id").getAsString();
+    assertEquals(cardId, "pFS7Fjg9kqcMOBtl3bFn");
+
+    // 展示实际用法
+    String extractedCardId = extractCardId(result);
+    assertEquals(extractedCardId, "pFS7Fjg9kqcMOBtl3bFn");
+  }
+
+  /**
+   * 提取card_id的示例方法
+   */
+  private String extractCardId(FavorStocksGetResult result) {
+    return getStringFieldSafely(result, "card_id");
+  }
+
+  /**
+   * 安全地从结果中获取字符串字段的工具方法
+   */
+  private String getStringFieldSafely(BaseWxPayV3Result result, String fieldName) {
+    String rawJson = result.getRawJsonString();
+    if (rawJson == null) return null;
+    
+    try {
+      JsonElement jsonElement = JsonParser.parseString(rawJson);
+      if (jsonElement.getAsJsonObject().has(fieldName)) {
+        JsonElement fieldElement = jsonElement.getAsJsonObject().get(fieldName);
+        return fieldElement.isJsonNull() ? null : fieldElement.getAsString();
+      }
+    } catch (Exception e) {
+      // 解析失败时返回null
+    }
+    return null;
+  }
+}
\ No newline at end of file
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java
index 963afb2618..e7a22ee6cd 100644
--- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java
@@ -119,7 +119,7 @@ public void testFromXMLFastMode() throws WxPayException {
       refundNotifyResult.loadReqInfo(xmlDecryptedReqInfo);
       assertEquals(refundNotifyResult.getReqInfo().getRefundFee().intValue(), 15);
       assertEquals(refundNotifyResult.getReqInfo().getRefundStatus(), "SUCCESS");
-      assertEquals(refundNotifyResult.getReqInfo().getRefundRecvAccout(), "用户零钱");
+      assertEquals(refundNotifyResult.getReqInfo().getRefundRecvAccount(), "用户零钱");
       System.out.println(refundNotifyResult);
     } finally {
       XmlConfig.fastMode = false;
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/payscore/WxPartnerPayScoreRequestTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/payscore/WxPartnerPayScoreRequestTest.java
new file mode 100644
index 0000000000..7b475d84a0
--- /dev/null
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/payscore/WxPartnerPayScoreRequestTest.java
@@ -0,0 +1,45 @@
+package com.github.binarywang.wxpay.bean.payscore;
+
+import org.testng.annotations.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author <a href="https://github.com/binarywang">Binary Wang</a>
+ * created on  2020-07-11
+ */
+public class WxPartnerPayScoreRequestTest {
+
+  @Test
+  public void testToJson() {
+    WxPartnerPayScoreRequest request = WxPartnerPayScoreRequest.builder()
+      .outOrderNo("QLS202005201058000201")
+      .appid("123")
+      .serviceId("345")
+      .serviceIntroduction("租借服务")
+      .timeRange(new TimeRange("20230901011023", "20230930235959","开始时间","结束时间"))
+      .device(new Device("deviceId","deviceId","212323232"))
+      .build();
+    System.out.println(request.toJson());
+    String expectedJson =
+      "{\"out_order_no\":\"QLS202005201058000201\",\"appid\":\"123\",\"service_id\":\"345\",\"service_introduction\":\"租借服务\",\"time_range\":{\"start_time\":\"20230901011023\",\"end_time\":\"20230930235959\",\"start_time_remark\":\"开始时间\",\"end_time_remark\":\"结束时间\"},\"device\":{\"start_device_id\":\"deviceId\",\"end_device_id\":\"deviceId\",\"materiel_no\":\"212323232\"}}";
+    assertThat(request.toJson()).isEqualTo(expectedJson);
+//    {
+//      "out_order_no": "QLS202005201058000201",
+//      "appid": "123",
+//      "service_id": "345",
+//      "service_introduction": "租借服务",
+//      "time_range": {
+//      "start_time": "20230901011023",
+//        "end_time": "20230930235959",
+//        "start_time_remark": "开始时间",
+//        "end_time_remark": "结束时间"
+//    },
+//      "device": {
+//      "start_device_id": "deviceId",
+//        "end_device_id": "deviceId",
+//        "materiel_no": "212323232"
+//    }
+//    }
+  }
+}
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/payscore/WxPayScoreRequestTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/payscore/WxPayScoreRequestTest.java
index 5d29f15a76..15f3f3abae 100644
--- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/payscore/WxPayScoreRequestTest.java
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/payscore/WxPayScoreRequestTest.java
@@ -2,6 +2,8 @@
 
 import org.testng.annotations.Test;
 
+import static org.assertj.core.api.Assertions.assertThat;
+
 /**
  * @author <a href="https://github.com/binarywang">Binary Wang</a>
  * created on  2020-07-11
@@ -15,40 +17,29 @@ public void testToJson() {
       .serviceId("345")
       .serviceIntroduction("租借服务")
       .timeRange(new TimeRange("20230901011023", "20230930235959","开始时间","结束时间"))
+      .device(new Device("deviceId","deviceId","212323232"))
       .build();
-    System.out.println(request.toJson());
-    /*    {
-      "out_order_no":"QLS202005201058000201",
-      "appid":"123",
-      "service_id":"345",
-      "service_introduction":"租借服务",
-      "time_range":{
-      "start_time":"OnAccept",
-        "end_time":"20200520225840"
-    },
-      "location":{
-      "start_location":"山",
-        "end_location":"山"
-    },
-      "risk_fund":{
-      "name":"DEPOSIT",
-        "amount":200,
-        "description":"丢失偿还费用2元/台"
-    },
-      "attach":"",
-      "notify_url":"/pay/notify/payScore",
-      "openid":"",
-      "need_user_confirm":true,
-      "profit_sharing":false,
-      "post_payments":[
-      {
-        "name":"租借服务",
-        "amount":100,
-        "description":"服务费：1元/台",
-        "count":1
-      }
-    ],
-      "total_amount":0
-    }*/
+    String json = request.toJson();
+    System.out.println(json);
+
+    String expectedJson = "{\"out_order_no\":\"QLS202005201058000201\",\"appid\":\"123\",\"service_id\":\"345\",\"service_introduction\":\"租借服务\",\"time_range\":{\"start_time\":\"20230901011023\",\"end_time\":\"20230930235959\",\"start_time_remark\":\"开始时间\",\"end_time_remark\":\"结束时间\"},\"device\":{\"start_device_id\":\"deviceId\",\"end_device_id\":\"deviceId\",\"materiel_no\":\"212323232\"}}";
+    assertThat(request.toJson()).isEqualTo(expectedJson);
+//    {
+//      "out_order_no": "QLS202005201058000201",
+//      "appid": "123",
+//      "service_id": "345",
+//      "service_introduction": "租借服务",
+//      "time_range": {
+//      "start_time": "20230901011023",
+//        "end_time": "20230930235959",
+//        "start_time_remark": "开始时间",
+//        "end_time_remark": "结束时间"
+//    },
+//      "device": {
+//      "start_device_id": "deviceId",
+//        "end_device_id": "deviceId",
+//        "materiel_no": "212323232"
+//    }
+//    }
   }
 }
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/request/CombineCloseRequestTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/request/CombineCloseRequestTest.java
new file mode 100644
index 0000000000..aaaa693324
--- /dev/null
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/request/CombineCloseRequestTest.java
@@ -0,0 +1,47 @@
+package com.github.binarywang.wxpay.bean.request;
+
+import com.google.gson.Gson;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author <a href="https://github.com/binarywang">Binary Wang</a>
+ * created on  2024-12-19
+ */
+public class CombineCloseRequestTest {
+
+  @Test
+  public void testSerialization() {
+    CombineCloseRequest request = new CombineCloseRequest();
+    request.setCombineAppid("wxd678efh567hg6787");
+    request.setCombineOutTradeNo("P20150806125346");
+
+    CombineCloseRequest.SubOrders subOrder = new CombineCloseRequest.SubOrders();
+    subOrder.setMchid("1900000109");
+    subOrder.setOutTradeNo("20150806125346");
+    subOrder.setSubMchid("1230000109");
+    subOrder.setSubAppid("wxd678efh567hg6999");
+
+    request.setSubOrders(Arrays.asList(subOrder));
+
+    Gson gson = new Gson();
+    String json = gson.toJson(request);
+
+    // Verify that the JSON contains the new fields
+    assertThat(json).contains("\"sub_mchid\":\"1230000109\"");
+    assertThat(json).contains("\"sub_appid\":\"wxd678efh567hg6999\"");
+    assertThat(json).contains("\"combine_appid\":\"wxd678efh567hg6787\"");
+    assertThat(json).contains("\"mchid\":\"1900000109\"");
+    assertThat(json).contains("\"out_trade_no\":\"20150806125346\"");
+
+    // Verify deserialization works
+    CombineCloseRequest deserializedRequest = gson.fromJson(json, CombineCloseRequest.class);
+    assertThat(deserializedRequest.getCombineAppid()).isEqualTo("wxd678efh567hg6787");
+    assertThat(deserializedRequest.getSubOrders()).hasSize(1);
+    assertThat(deserializedRequest.getSubOrders().get(0).getSubMchid()).isEqualTo("1230000109");
+    assertThat(deserializedRequest.getSubOrders().get(0).getSubAppid()).isEqualTo("wxd678efh567hg6999");
+  }
+}
\ No newline at end of file
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/CustomizedWxPayConfigTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/CustomizedWxPayConfigTest.java
index a42026e3ee..3b2bdfeaa6 100644
--- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/CustomizedWxPayConfigTest.java
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/CustomizedWxPayConfigTest.java
@@ -1,5 +1,9 @@
 package com.github.binarywang.wxpay.config;
 
+import static org.testng.Assert.assertEquals;
+
+import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryV3Result;
+import com.github.binarywang.wxpay.constant.WxPayErrorCode;
 import com.github.binarywang.wxpay.exception.WxPayException;
 import com.github.binarywang.wxpay.service.WxPayService;
 import com.github.binarywang.wxpay.testbase.CustomizedApiTestModule;
@@ -30,10 +34,9 @@ public void testCustomizerHttpClient() {
 
   public void testCustomizerV3HttpClient() {
     try {
-      wxPayService.queryOrderV3("a", null);
+      WxPayOrderQueryV3Result result = wxPayService.queryOrderV3("a", null);
     } catch (WxPayException e) {
-      // ignore
-      e.printStackTrace();
+      assertEquals(e.getErrCode(), WxPayErrorCode.RefundQuery.PARAM_ERROR);
     }
   }
 }
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/WxPayConfigTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/WxPayConfigTest.java
index 72750e01cd..46bc23aac2 100644
--- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/WxPayConfigTest.java
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/config/WxPayConfigTest.java
@@ -1,16 +1,7 @@
 package com.github.binarywang.wxpay.config;
 
-import com.github.binarywang.wxpay.exception.WxPayException;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.pqc.jcajce.provider.util.KeyUtil;
 import org.testng.annotations.Test;
 
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.SecureRandom;
-import java.security.Security;
-import java.util.Base64;
-
 /**
  * <pre>
  *  Created by BinaryWang on 2017/6/18.
@@ -54,19 +45,4 @@ public void testInitSSLContext_base64() throws Exception {
     payConfig.initSSLContext();
   }
 
-
-  @Test
-  public void testInitApiV3HttpClient() throws Exception {
-    Security.addProvider(new BouncyCastleProvider());
-    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA","BC");
-    keyPairGenerator.initialize(2048,new SecureRandom());
-    KeyPair keyPair = keyPairGenerator.genKeyPair();
-    byte[] encoded = keyPair.getPrivate().getEncoded();
-    // 模拟用户配置
-    String privateKeyString = Base64.getEncoder().encodeToString(encoded);
-    payConfig.setPrivateKeyString(privateKeyString);
-    payConfig.setApiV3Key("Test");
-    payConfig.initApiV3HttpClient();
-  }
-
 }
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/ConnectionPoolUsageExampleTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/ConnectionPoolUsageExampleTest.java
new file mode 100644
index 0000000000..143743ffcf
--- /dev/null
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/ConnectionPoolUsageExampleTest.java
@@ -0,0 +1,61 @@
+package com.github.binarywang.wxpay.service.impl;
+
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * 演示连接池功能的示例测试
+ */
+public class ConnectionPoolUsageExampleTest {
+
+  @Test
+  public void demonstrateConnectionPoolUsage() throws Exception {
+    // 1. 创建配置并设置连接池参数
+    WxPayConfig config = new WxPayConfig();
+    config.setAppId("wx123456789");
+    config.setMchId("1234567890");
+    config.setMchKey("32位商户密钥32位商户密钥32位商户密钥");
+    
+    // 设置连接池参数（可选，有默认值）
+    config.setMaxConnTotal(50);  // 最大连接数，默认20
+    config.setMaxConnPerRoute(20); // 每个路由最大连接数，默认10
+    
+    // 2. 初始化连接池
+    CloseableHttpClient pooledClient = config.initHttpClient();
+    Assert.assertNotNull(pooledClient);
+    
+    // 3. 创建支付服务实例
+    WxPayServiceApacheHttpImpl payService = new WxPayServiceApacheHttpImpl();
+    payService.setConfig(config);
+    
+    // 4. 现在所有的HTTP请求都会使用连接池
+    // 对于非SSL请求，会复用同一个HttpClient实例
+    CloseableHttpClient client1 = payService.createHttpClient(false);
+    CloseableHttpClient client2 = payService.createHttpClient(false);
+    Assert.assertSame(client1, client2, "非SSL请求应该复用同一个客户端实例");
+    
+    // 对于SSL请求，也会复用同一个SSL HttpClient实例（需要配置证书后）
+    System.out.println("连接池配置成功！");
+    System.out.println("最大连接数：" + config.getMaxConnTotal());
+    System.out.println("每路由最大连接数：" + config.getMaxConnPerRoute());
+  }
+  
+  @Test
+  public void demonstrateDefaultConfiguration() throws Exception {
+    // 使用默认配置的示例
+    WxPayConfig config = new WxPayConfig();
+    config.setAppId("wx123456789");
+    config.setMchId("1234567890");
+    config.setMchKey("32位商户密钥32位商户密钥32位商户密钥");
+    
+    // 不设置连接池参数，使用默认值
+    CloseableHttpClient client = config.initHttpClient();
+    Assert.assertNotNull(client);
+    
+    // 验证默认配置
+    Assert.assertEquals(config.getMaxConnTotal(), 20, "默认最大连接数应该是20");
+    Assert.assertEquals(config.getMaxConnPerRoute(), 10, "默认每路由最大连接数应该是10");
+  }
+}
\ No newline at end of file
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/TransferServiceImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/TransferServiceImplTest.java
index 7f89bd4721..10c2a5da66 100644
--- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/TransferServiceImplTest.java
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/TransferServiceImplTest.java
@@ -2,6 +2,7 @@
 
 import com.github.binarywang.wxpay.bean.transfer.QueryTransferBatchesRequest;
 import com.github.binarywang.wxpay.bean.transfer.TransferBatchesRequest;
+import com.github.binarywang.wxpay.bean.transfer.TransferBillsRequest;
 import com.github.binarywang.wxpay.exception.WxPayException;
 import com.github.binarywang.wxpay.service.WxPayService;
 import com.github.binarywang.wxpay.testbase.ApiTestModule;
@@ -73,4 +74,32 @@ public void testTransferBatchesOutBatchNo() throws WxPayException {
   public void testTransferBatchesOutBatchNoDetail() throws WxPayException {
     log.info("商家明细单号查询明细单:{}", this.payService.getTransferService().transferBatchesOutBatchNoDetail("1655447999520", "1655447989156"));
   }
+
+  @Test
+  public void testTransferBills() throws WxPayException {
+    TransferBillsRequest transferBillsRequest = TransferBillsRequest.newBuilder()
+      .appid("wxf636efh5xxxxx")
+      .outBillNo("1655447989156")
+      .transferSceneId("1005")
+      .transferAmount(100)
+      .transferRemark("测试转账")
+      .openid("oX_7Jzr9gSZz4X_Xc9-_7HGf8XzI")
+      .userName("测试用户").build();
+    log.info("发起商家转账:{}", this.payService.getTransferService().transferBills(transferBillsRequest));
+  }
+
+  @Test
+  public void testTransformBillsCancel() throws WxPayException {
+    log.info("撤销商家转账:{}", this.payService.getTransferService().transformBillsCancel("123456"));
+  }
+
+  @Test
+  public void testGetBillsByOutBillNo() throws WxPayException {
+    log.info("商户单号查询转账单：{}", this.payService.getTransferService().getBillsByOutBillNo("123456"));
+  }
+
+  @Test
+  public void testGetBillsByTransferBillNo() throws WxPayException {
+    log.info("微信单号查询转账单：{}", this.payService.getTransferService().getBillsByTransferBillNo("123456"));
+  }
 }
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImplConnectionPoolTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImplConnectionPoolTest.java
new file mode 100644
index 0000000000..393d601a69
--- /dev/null
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/WxPayServiceApacheHttpImplConnectionPoolTest.java
@@ -0,0 +1,86 @@
+package com.github.binarywang.wxpay.service.impl;
+
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * 测试WxPayServiceApacheHttpImpl的连接池功能
+ */
+public class WxPayServiceApacheHttpImplConnectionPoolTest {
+
+  @Test
+  public void testHttpClientConnectionPool() throws Exception {
+    WxPayConfig config = new WxPayConfig();
+    config.setAppId("test-app-id");
+    config.setMchId("test-mch-id");
+    config.setMchKey("test-mch-key");
+    
+    // 测试初始化连接池
+    CloseableHttpClient httpClient1 = config.initHttpClient();
+    Assert.assertNotNull(httpClient1, "HttpClient should not be null");
+    
+    // 再次获取，应该返回同一个实例
+    CloseableHttpClient httpClient2 = config.getHttpClient();
+    Assert.assertSame(httpClient1, httpClient2, "Should return the same HttpClient instance");
+    
+    // 验证连接池配置
+    WxPayServiceApacheHttpImpl service = new WxPayServiceApacheHttpImpl();
+    service.setConfig(config);
+    
+    // 测试不使用SSL的情况下应该使用连接池
+    CloseableHttpClient clientForNonSSL = service.createHttpClient(false);
+    Assert.assertSame(httpClient1, clientForNonSSL, "Should use pooled client for non-SSL requests");
+  }
+  
+  @Test
+  public void testSslHttpClientConnectionPool() throws Exception {
+    WxPayConfig config = new WxPayConfig();
+    config.setAppId("test-app-id");
+    config.setMchId("test-mch-id");
+    config.setMchKey("test-mch-key");
+    
+    // 为了测试SSL客户端，我们需要设置一些基本的SSL配置
+    // 注意：在实际使用中需要提供真实的证书
+    try {
+      CloseableHttpClient sslClient1 = config.initSslHttpClient();
+      Assert.assertNotNull(sslClient1, "SSL HttpClient should not be null");
+      
+      CloseableHttpClient sslClient2 = config.getSslHttpClient();
+      Assert.assertSame(sslClient1, sslClient2, "Should return the same SSL HttpClient instance");
+      
+      WxPayServiceApacheHttpImpl service = new WxPayServiceApacheHttpImpl();
+      service.setConfig(config);
+      
+      // 测试使用SSL的情况下应该使用SSL连接池
+      CloseableHttpClient clientForSSL = service.createHttpClient(true);
+      Assert.assertSame(sslClient1, clientForSSL, "Should use pooled SSL client for SSL requests");
+      
+    } catch (WxPayException e) {
+      // SSL初始化失败是预期的，因为我们没有提供真实的证书
+      // 这里主要是测试代码路径是否正确
+      Assert.assertTrue(e.getMessage().contains("证书") || e.getMessage().contains("商户号"), 
+          "Should fail with certificate or merchant ID related error");
+    }
+  }
+  
+  @Test
+  public void testConnectionPoolConfiguration() throws Exception {
+    WxPayConfig config = new WxPayConfig();
+    config.setAppId("test-app-id");
+    config.setMchId("test-mch-id");
+    config.setMchKey("test-mch-key");
+    config.setMaxConnTotal(50);
+    config.setMaxConnPerRoute(20);
+    
+    CloseableHttpClient httpClient = config.initHttpClient();
+    Assert.assertNotNull(httpClient, "HttpClient should not be null");
+    
+    // 验证配置值是否正确设置
+    Assert.assertEquals(config.getMaxConnTotal(), 50, "Max total connections should be 50");
+    Assert.assertEquals(config.getMaxConnPerRoute(), 20, "Max connections per route should be 20");
+  }
+}
\ No newline at end of file
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/testbase/CustomizedApiTestModule.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/testbase/CustomizedApiTestModule.java
index a0cc399ea9..484227e34e 100644
--- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/testbase/CustomizedApiTestModule.java
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/testbase/CustomizedApiTestModule.java
@@ -6,15 +6,14 @@
 import com.google.inject.Binder;
 import com.google.inject.Module;
 import com.thoughtworks.xstream.XStream;
+import java.io.*;
+import java.nio.charset.StandardCharsets;
 import me.chanjar.weixin.common.error.WxRuntimeException;
 import me.chanjar.weixin.common.util.xml.XStreamInitializer;
 import org.apache.http.HttpRequestInterceptor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.IOException;
-import java.io.InputStream;
-
 /**
  * The type Api test module.
  */
@@ -39,7 +38,22 @@ public void configure(Binder binder) {
       config.setHttpClientBuilderCustomizer((builder) -> {
         builder.addInterceptorLast((HttpRequestInterceptor) (r, c) -> System.out.println("--------> HttpRequestInterceptor ..."));
       });
+      try (FileInputStream fis = new FileInputStream(config.getPrivateKeyPath());
+           InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
+           BufferedReader reader = new BufferedReader(isr)) {
+
+        StringBuilder stringBuilder = new StringBuilder();
+        String line;
+        while ((line = reader.readLine()) != null) {
+          stringBuilder.append(line);
+          stringBuilder.append(System.lineSeparator());
+        }
 
+        String fileContent = stringBuilder.toString();
+        config.setPrivateKeyString(fileContent);
+        System.out.println(fileContent);
+
+      }
       WxPayService wxService = new WxPayServiceImpl();
       wxService.setConfig(config);
 
diff --git a/weixin-java-pay/src/test/resources/test-config.sample.xml b/weixin-java-pay/src/test/resources/test-config.sample.xml
index a63cd8dc30..e9d383dd19 100644
--- a/weixin-java-pay/src/test/resources/test-config.sample.xml
+++ b/weixin-java-pay/src/test/resources/test-config.sample.xml
@@ -18,6 +18,7 @@
   <certSerialNo>apiV3 证书序列号值</certSerialNo>
   <privateKeyPath>apiclient_key.pem证书文件的绝对路径或者以classpath:开头的类路径.</privateKeyPath>
   <privateCertPath>apiclient_cert.pem证书文件的绝对路径或者以classpath:开头的类路径.</privateCertPath>
+  <publicKeyPath>pub_key.pem证书文件的绝对路径或者以classpath:开头的类路径.</publicKeyPath>
 
   <!-- other配置 -->
   <openid>某个openId</openid>
diff --git a/weixin-java-qidian/pom.xml b/weixin-java-qidian/pom.xml
index 77918c72ab..a7aef14c2b 100644
--- a/weixin-java-qidian/pom.xml
+++ b/weixin-java-qidian/pom.xml
@@ -7,7 +7,7 @@
   <parent>
     <groupId>com.github.binarywang</groupId>
     <artifactId>wx-java</artifactId>
-    <version>4.6.7.B</version>
+    <version>4.7.7.B</version>
   </parent>
 
   <artifactId>weixin-java-qidian</artifactId>
@@ -31,6 +31,11 @@
       <artifactId>okhttp</artifactId>
       <scope>provided</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.httpcomponents.client5</groupId>
+      <artifactId>httpclient5</artifactId>
+      <scope>provided</scope>
+    </dependency>
 
     <dependency>
       <groupId>org.testng</groupId>
diff --git a/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/WxQidianService.java b/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/WxQidianService.java
index aeea34e829..b7c5a64c7a 100644
--- a/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/WxQidianService.java
+++ b/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/WxQidianService.java
@@ -340,7 +340,7 @@ public interface WxQidianService extends WxService {
    *
    * @return RequestHttp对象 request http
    */
-  RequestHttp getRequestHttp();
+  RequestHttp<?, ?> getRequestHttp();
 
   WxQidianDialService getDialService();
 
diff --git a/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/impl/BaseWxQidianServiceImpl.java b/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/impl/BaseWxQidianServiceImpl.java
index 2b7c7057a4..3f5023afe7 100644
--- a/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/impl/BaseWxQidianServiceImpl.java
+++ b/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/impl/BaseWxQidianServiceImpl.java
@@ -56,7 +56,7 @@ public boolean checkSignature(String timestamp, String nonce, String signature)
     try {
       return SHA1.gen(this.getWxMpConfigStorage().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;
     }
   }
@@ -405,7 +405,7 @@ public void setMaxRetryTimes(int maxRetryTimes) {
   }
 
   @Override
-  public RequestHttp getRequestHttp() {
+  public RequestHttp<H, P> getRequestHttp() {
     return this;
   }
 
diff --git a/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/impl/WxQidianServiceHttpClientImpl.java b/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/impl/WxQidianServiceHttpClientImpl.java
index cd39f1a68e..2fc779a949 100644
--- a/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/impl/WxQidianServiceHttpClientImpl.java
+++ b/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/impl/WxQidianServiceHttpClientImpl.java
@@ -2,15 +2,14 @@
 
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.error.WxRuntimeException;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
+import me.chanjar.weixin.common.util.http.apache.ApacheBasicResponseHandler;
 import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
 import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
 import me.chanjar.weixin.qidian.config.WxQidianConfigStorage;
 import org.apache.http.HttpHost;
 import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.client.BasicResponseHandler;
 import org.apache.http.impl.client.CloseableHttpClient;
 
 import java.io.IOException;
@@ -39,8 +38,8 @@ public HttpHost getRequestHttpProxy() {
   }
 
   @Override
-  public HttpType getRequestType() {
-    return HttpType.APACHE_HTTP;
+  public HttpClientType getRequestType() {
+    return HttpClientType.APACHE_HTTP;
   }
 
   @Override
@@ -86,11 +85,8 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
           RequestConfig requestConfig = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
           httpGet.setConfig(requestConfig);
         }
-        try (CloseableHttpResponse response = getRequestHttpClient().execute(httpGet)) {
-          return this.extractAccessToken(new BasicResponseHandler().handleResponse(response));
-        } finally {
-          httpGet.releaseConnection();
-        }
+        String responseContent = getRequestHttpClient().execute(httpGet, ApacheBasicResponseHandler.INSTANCE);
+        return this.extractAccessToken(responseContent);
       } catch (IOException e) {
         throw new WxRuntimeException(e);
       }
diff --git a/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/impl/WxQidianServiceHttpComponentsImpl.java b/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/impl/WxQidianServiceHttpComponentsImpl.java
new file mode 100644
index 0000000000..a5cc23f0a2
--- /dev/null
+++ b/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/impl/WxQidianServiceHttpComponentsImpl.java
@@ -0,0 +1,99 @@
+package me.chanjar.weixin.qidian.api.impl;
+
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.error.WxRuntimeException;
+import me.chanjar.weixin.common.util.http.HttpClientType;
+import me.chanjar.weixin.common.util.http.hc.BasicResponseHandler;
+import me.chanjar.weixin.common.util.http.hc.DefaultHttpComponentsClientBuilder;
+import me.chanjar.weixin.common.util.http.hc.HttpComponentsClientBuilder;
+import me.chanjar.weixin.qidian.config.WxQidianConfigStorage;
+import org.apache.hc.client5.http.classic.methods.HttpGet;
+import org.apache.hc.client5.http.config.RequestConfig;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.HttpHost;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+
+import static me.chanjar.weixin.qidian.enums.WxQidianApiUrl.Other.GET_ACCESS_TOKEN_URL;
+
+/**
+ * apache http client5 方式实现.
+ *
+ * @author altusea
+ */
+public class WxQidianServiceHttpComponentsImpl extends BaseWxQidianServiceImpl<CloseableHttpClient, HttpHost> {
+  private CloseableHttpClient httpClient;
+  private HttpHost httpProxy;
+
+  @Override
+  public CloseableHttpClient getRequestHttpClient() {
+    return httpClient;
+  }
+
+  @Override
+  public HttpHost getRequestHttpProxy() {
+    return httpProxy;
+  }
+
+  @Override
+  public HttpClientType getRequestType() {
+    return HttpClientType.HTTP_COMPONENTS;
+  }
+
+  @Override
+  public void initHttp() {
+    WxQidianConfigStorage configStorage = this.getWxMpConfigStorage();
+    HttpComponentsClientBuilder apacheHttpClientBuilder = DefaultHttpComponentsClientBuilder.get();
+
+    apacheHttpClientBuilder.httpProxyHost(configStorage.getHttpProxyHost())
+        .httpProxyPort(configStorage.getHttpProxyPort()).httpProxyUsername(configStorage.getHttpProxyUsername())
+        .httpProxyPassword(configStorage.getHttpProxyPassword().toCharArray());
+
+    if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) {
+      this.httpProxy = new HttpHost(configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort());
+    }
+
+    this.httpClient = apacheHttpClientBuilder.build();
+  }
+
+  @Override
+  public String getAccessToken(boolean forceRefresh) throws WxErrorException {
+    final WxQidianConfigStorage config = this.getWxMpConfigStorage();
+    if (!config.isAccessTokenExpired() && !forceRefresh) {
+      return config.getAccessToken();
+    }
+
+    Lock lock = config.getAccessTokenLock();
+    boolean locked = false;
+    try {
+      do {
+        locked = lock.tryLock(100, TimeUnit.MILLISECONDS);
+        if (!forceRefresh && !config.isAccessTokenExpired()) {
+          return config.getAccessToken();
+        }
+      } while (!locked);
+
+      String url = String.format(GET_ACCESS_TOKEN_URL.getUrl(config), config.getAppId(), config.getSecret());
+      try {
+        HttpGet httpGet = new HttpGet(url);
+        if (this.getRequestHttpProxy() != null) {
+          RequestConfig requestConfig = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
+          httpGet.setConfig(requestConfig);
+        }
+        String responseContent = getRequestHttpClient().execute(httpGet, BasicResponseHandler.INSTANCE);
+        return this.extractAccessToken(responseContent);
+      } catch (IOException e) {
+        throw new WxRuntimeException(e);
+      }
+    } catch (InterruptedException e) {
+      throw new WxRuntimeException(e);
+    } finally {
+      if (locked) {
+        lock.unlock();
+      }
+    }
+  }
+
+}
diff --git a/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/impl/WxQidianServiceJoddHttpImpl.java b/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/impl/WxQidianServiceJoddHttpImpl.java
index 41ec6d9f38..18a2262a3f 100644
--- a/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/impl/WxQidianServiceJoddHttpImpl.java
+++ b/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/impl/WxQidianServiceJoddHttpImpl.java
@@ -6,7 +6,7 @@
 import jodd.http.net.SocketHttpConnectionProvider;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.error.WxRuntimeException;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
 import me.chanjar.weixin.qidian.config.WxQidianConfigStorage;
 
 import java.util.concurrent.TimeUnit;
@@ -34,8 +34,8 @@ public ProxyInfo getRequestHttpProxy() {
   }
 
   @Override
-  public HttpType getRequestType() {
-    return HttpType.JODD_HTTP;
+  public HttpClientType getRequestType() {
+    return HttpClientType.JODD_HTTP;
   }
 
   @Override
diff --git a/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/impl/WxQidianServiceOkHttpImpl.java b/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/impl/WxQidianServiceOkHttpImpl.java
index 92cf51e670..5ff6734ccb 100644
--- a/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/impl/WxQidianServiceOkHttpImpl.java
+++ b/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/api/impl/WxQidianServiceOkHttpImpl.java
@@ -2,7 +2,7 @@
 
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.common.error.WxRuntimeException;
-import me.chanjar.weixin.common.util.http.HttpType;
+import me.chanjar.weixin.common.util.http.HttpClientType;
 import me.chanjar.weixin.common.util.http.okhttp.DefaultOkHttpClientBuilder;
 import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
 import me.chanjar.weixin.qidian.config.WxQidianConfigStorage;
@@ -35,8 +35,8 @@ public OkHttpProxyInfo getRequestHttpProxy() {
   }
 
   @Override
-  public HttpType getRequestType() {
-    return HttpType.OK_HTTP;
+  public HttpClientType getRequestType() {
+    return HttpClientType.OK_HTTP;
   }
 
   @Override
@@ -60,9 +60,7 @@ public String getAccessToken(boolean forceRefresh) throws WxErrorException {
       Request request = new Request.Builder().url(url).get().build();
       Response response = getRequestHttpClient().newCall(request).execute();
       return this.extractAccessToken(Objects.requireNonNull(response.body()).string());
-    } catch (IOException e) {
-      throw new WxRuntimeException(e);
-    } catch (InterruptedException e) {
+    } catch (IOException | InterruptedException e) {
       throw new WxRuntimeException(e);
     } finally {
       if (locked) {
diff --git a/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/util/WxQidianConfigStorageHolder.java b/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/util/WxQidianConfigStorageHolder.java
index ec2e872942..2b47667996 100644
--- a/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/util/WxQidianConfigStorageHolder.java
+++ b/weixin-java-qidian/src/main/java/me/chanjar/weixin/qidian/util/WxQidianConfigStorageHolder.java
@@ -5,12 +5,7 @@
  * created on  2020年12月26日
  */
 public class WxQidianConfigStorageHolder {
-  private static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<String>() {
-    @Override
-    protected String initialValue() {
-      return "default";
-    }
-  };
+  private static final ThreadLocal<String> THREAD_LOCAL = ThreadLocal.withInitial(() -> "default");
 
   public static String get() {
     return THREAD_LOCAL.get();
