# fastweixin
**Repository Path**: candy_code/fastweixin
## Basic Information
- **Project Name**: fastweixin
- **Description**: 基于开源的fastweixin修订的一套用于快速开发微信公众号功能的sdk
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-12-03
- **Last Updated**: 2026-11-05
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# fastweixin
fastweixin 是一个 Java 编写的微信开发 SDK,覆盖**公众号、小程序、企业微信(企业号)、开放平台、微信支付**五大体系的常用接口。
设计目标只有一个:**让调用者直接通过 SDK 调用微信接口,而不需要阅读微信官方文档。**
- 凭证自动管理:传入 appid + secret,access_token / jsapi_ticket 的获取、缓存、过期前自动刷新全部由 SDK 完成;
- 编译期区分凭证:哪个接口需要什么凭证,构造函数签名就是说明书,传错凭证 IDE 直接红线;
- 消息服务器开箱即用:继承、重写即可监听所有类型的微信消息与事件,同时提供 springmvc / servlet 两种集成方式;
- URL 模板机制:占位符名即微信真实参数名,缺凭证时在请求发出前抛出写明"缺什么、怎么办"的自解释异常,彻底消灭静默失败。
**环境要求**:JDK 1.8+,依赖 httpcomponents 4.3.x(HTTP)、fastjson(JSON)。
---
# 目录
- [1. 架构介绍](#1-架构介绍)
- [1.1 模块总览](#11-模块总览)
- [1.2 凭证体系(核心设计)](#12-凭证体系核心设计)
- [1.3 分层不变量](#13-分层不变量)
- [2. 快速开始](#2-快速开始)
- [2.1 Maven 引入](#21-maven-引入)
- [2.2 最小示例:托管模式调用一个接口](#22-最小示例托管模式调用一个接口)
- [2.3 自维护模式](#23-自维护模式)
- [3. 消息服务器(接收与回复消息)](#3-消息服务器接收与回复消息)
- [4. 使用手册:公众号 API](#4-使用手册公众号-api)
- [5. 使用手册:小程序 API](#5-使用手册小程序-api)
- [6. 使用手册:企业微信 API](#6-使用手册企业微信-api)
- [7. 使用手册:开放平台 API](#7-使用手册开放平台-api)
- [8. 使用手册:微信支付](#8-使用手册微信支付)
- [9. 统一返回值与异常处理](#9-统一返回值与异常处理)
- [10. 版本升级](#10-版本升级)
---
# 1. 架构介绍
## 1.1 模块总览
```
com.fastweixin
├── api 公众号 + 小程序 API(WxMenuAPI、WxUserAPI……)
│ ├── config 凭证层:AccessTokenProvider / JsApiTicketProvider /
│ │ ApiConfig / TokenCredential / JsTicketCredential
│ ├── entity 请求实体(Menu、Article、TemplateMsg……)
│ ├── enums 枚举(MediaType、OauthScope、QrcodeType、ResultType……)
│ └── response 响应对象(均继承 BaseResponse)
├── company 企业微信 API(独立凭证体系,与公众号编译期隔离)
├── mina 小程序 API(小程序码、订阅消息、模板消息、手机号)
├── open 开放平台 API(第三方平台授权)
├── v3 微信支付 V3(独立签名体系,不依赖凭证层)
├── message 消息对象(收到的请求消息 req/ 与回复消息)
├── servlet 消息服务器框架(WeixinSupport / WeixinControllerSupport……)
├── handle 自定义消息/事件处理器接口(MessageHandle、EventHandle)
├── exception WeixinException
└── util 工具类(NetWorkKit、UrlTemplateKit、JsApiUtil……)
```
## 1.2 凭证体系(核心设计)
调用者只需要回答两个问题:**手里有什么凭证**、**token 想让谁管**。
### 模式 1:SDK 托管(推荐)
```java
ApiConfig config = new ApiConfig(appid, secret);
```
一个对象传遍所有 API。access_token 与 jsapi_ticket 的获取、缓存、过期前自动刷新(提前约 100 秒)全部由 SDK 完成,调用者完全不需要知道 token 的存在。多实例场景下通过 Observer 机制(`ConfigChangeNotice`)同步 token。
### 模式 2:调用者自维护
```java
TokenCredential token = new TokenCredential(accessToken); // 只承载 access_token
JsTicketCredential ticket = new JsTicketCredential(jsapiTicket); // 只承载 jsapi_ticket
```
适用于 token 来自调用者自己的定时任务、网关或第三方授权的场景。SDK 绝不主动刷新,过期后由调用者调用 `updateAccessToken()` / `updateJsApiTicket()` 更新(volatile 字段,线程安全)。
### 编译期区分:构造签名即需求说明
| API 构造参数 | 含义 | 可传入 |
|---|---|---|
| `AccessTokenProvider` | 该接口需要 access_token | `ApiConfig` 或 `TokenCredential` |
| `JsApiTicketProvider` | 该接口需要 jsapi_ticket | `ApiConfig` 或 `JsTicketCredential` |
| `ApiConfig`(具体类) | 该接口需要 appid + secret | 仅 `ApiConfig` |
| `QyAccessTokenProvider` | 企业微信体系专用 | `QYAPIConfig` 或 `QyTokenCredential` |
`new WxTokenAPI(tokenCredential)` 传入编译失败——物理上只有 `ApiConfig` 能提供 appid+secret,传不进去就是不该传。同理,企业微信凭证传给公众号 API、公众号凭证传给企业微信 API 都是编译失败。"哪个接口需要什么凭证"这一知识从调用者脑中转移进了类型系统。
### URL 命名占位符
所有接口 URL 使用 `{name}` 命名占位符,占位符名即微信真实参数名,模板读起来即真实 URL:
```java
String url = BASE_API_URL + "cgi-bin/menu/create?access_token={access_token}";
String url = BASE_API_URL + "cgi-bin/token?grant_type=client_credential&appid={appid}&secret={secret}";
```
解析逻辑全库唯一(`UrlTemplateKit`),在请求发出前完成:
- 凭证有值 → 替换;
- 凭证提供不了 → 抛 `WeixinException`,消息包含接口 URL、缺失的参数、当前凭证类型与解决办法,例如:
`接口 [cgi-bin/menu/create?access_token={access_token}] 需要 {access_token},当前凭证[TokenCredential]无法提供该值。若使用 TokenCredential(自维护模式),请先调用 updateAccessToken() 填入有效的 access_token……`
## 1.3 层级架构
```
应用代码
│ 传入凭证对象
▼
API 层(WxBaseAPI / QYBaseAPI / OpenBaseAPI) ← 凭证止步于此:解析占位符、快速失败
│ 已拼装完成的真实 URL
▼
网络层(NetWorkKit) ← 与业务无关,纯 HTTP 收发
```
---
# 2. 快速开始
## 2.1 Maven 引入
```xml
club.yylyy
fastweixin
3.0.0
```
## 2.2 最小示例:托管模式调用一个接口
```java
// 1. 构造凭证(全局单例,请勿每次请求都新建)
ApiConfig config = new ApiConfig("yourAppid", "yourSecret");
// 2. 构造 API 并调用,token 由 SDK 自动管理
WxUserAPI userAPI = new WxUserAPI(config);
GetUserInfoResponse userInfo = userAPI.getUserInfo("openid_of_follower");
if (userInfo.isSuccess()) {
System.out.println("昵称: " + userInfo.getNickname());
} else {
System.out.println("失败: " + userInfo.getErrcode() + " " + userInfo.getErrmsg());
}
```
创建菜单、发送模板消息、JS-SDK 签名等所有接口同样是"构造凭证 → 构造 API → 调用"三步,无需关心 token。
## 2.3 自维护模式
适用于 access_token 由别的系统统一获取分发的场景:
```java
// 自维护 token:SDK 不刷新,过期由调用者更新
TokenCredential credential = new TokenCredential("accessTokenFromGateway");
WxMenuAPI menuAPI = new WxMenuAPI(credential);
// 需要用 token 换取 jsapi_ticket 时(ApiConfig 托管模式无需此步)
WxJsTicketApi jsTicketApi = new WxJsTicketApi(credential);
JsTicketResponse resp = jsTicketApi.getJsTicket(WxJsTicketApi.JsApiType.jsapi);
JsTicketCredential ticketCredential = new JsTicketCredential(resp.getTicket());
WxJsAPI jsAPI = new WxJsAPI(ticketCredential);
// token 过期后,由你的刷新任务更新(线程安全)
credential.updateAccessToken("newAccessToken");
```
---
# 3. 消息服务器(接收与回复消息)
消息服务器用于接收微信服务器推送的消息/事件并回复。核心类 `WeixinSupport` 完全独立、不依赖任何 web 框架,`WeixinControllerSupport` / `WeixinServletSupport` 是对 springmvc / servlet 的适配。
## 3.1 基于 springmvc
```java
@RestController
@RequestMapping("/weixin")
public class WeixinController extends WeixinControllerSupport {
// TOKEN,用于绑定微信服务器(在公众号后台"服务器配置"中填写的一致)
@Override
protected String getToken() {
return "myToken";
}
// 使用安全(加密)模式时重写,返回 APPID / AES 密钥;明文模式无需重写
@Override
protected String getAppId() { return null; }
@Override
protected String getAESKey() { return null; }
// 重写父类方法,处理对应的微信消息
@Override
protected BaseMsg handleTextMsg(TextReqMsg msg) {
return new TextMsg("服务器回复用户消息!");
}
// 可选:注册自定义消息/事件处理器,每个处理器只处理指定消息,适合业务复杂的场景
@Override
protected List initMessageHandles() {
return Collections.singletonList(new MyMessageHandle());
}
@Override
protected List initEventHandles() {
return Collections.singletonList(new MyEventHandle());
}
}
```
## 3.2 基于 servlet
```java
public class WeixinServlet extends WeixinServletSupport {
@Override
protected WeixinSupport getWeixinSupport() {
return new MyServletWeixinSupport();
}
}
public class MyServletWeixinSupport extends WeixinSupport {
@Override
protected String getToken() { return "myToken"; }
@Override
protected BaseMsg handleTextMsg(TextReqMsg msg) {
return new TextMsg("服务器回复用户消息!");
}
}
```
`web.xml` 配置:
```xml
weixin
xxx.xxx.WeixinServlet
weixin
/weixin
```
## 3.3 可重写的消息/事件处理方法
所有方法都有默认实现(返回 null 即不回复),按需重写即可:
| 方法 | 触发场景 |
|---|---|
| `handleTextMsg(TextReqMsg)` | 文本消息 |
| `handleImageMsg(ImageReqMsg)` | 图片消息 |
| `handleVoiceMsg(VoiceReqMsg)` | 语音消息 |
| `handleVideoMsg(VideoReqMsg)` | 视频消息 |
| `handleShortVideoMsg(VideoReqMsg)` | 小视频消息 |
| `handleLocationMsg(LocationReqMsg)` | 地理位置消息 |
| `handleLinkMsg(LinkReqMsg)` | 链接消息 |
| `handleSubscribe(BaseEvent)` | 关注事件 |
| `handleUnsubscribe(BaseEvent)` | 取消关注事件 |
| `handleQrCodeEvent(QrCodeEvent)` | 扫描带参二维码事件 |
| `handleLocationEvent(LocationEvent)` | 上报地理位置事件 |
| `handleMenuClickEvent(MenuEvent)` | 自定义菜单点击(CLICK)事件 |
| `handleMenuViewEvent(MenuEvent)` | 自定义菜单跳转(VIEW)事件 |
| `handleScanCodeEvent(ScanCodeEvent)` | 扫码推事件 |
| `handlePSendPicsInfoEvent(SendPicsInfoEvent)` | 弹出拍照/相册发图事件 |
| `handleTemplateMsgEvent(TemplateMsgEvent)` | 模板消息推送结果事件 |
| `handleDefaultMsg(BaseReqMsg)` | 未被上面方法覆盖的消息(兜底) |
| `handleDefaultEvent(BaseEvent)` | 未被上面方法覆盖的事件(兜底) |
回复消息类型:`TextMsg`、`ImageMsg`、`VoiceMsg`、`VideoMsg`、`MusicMsg`、`NewsMsg`(图文)。
---
# 4. 使用手册:公众号 API
本章所有 API 位于 `com.fastweixin.api` 包。除特别说明外:
- 构造参数 `AccessTokenProvider`:`ApiConfig`(托管)或 `TokenCredential`(自维护)均可;
- 返回对象均继承 `BaseResponse`,可用 `isSuccess()` / `isFailed()` 判断,`getErrcode()` / `getErrmsg()` 取错误详情;
- 返回 `ResultType` 的方法表示该接口只返回成功/失败状态。
## 4.1 WxTokenAPI —— 换取 access_token
**作用**:用 appid + secret 换取 access_token。**仅接受 `ApiConfig`**(物理上只有它能提供 appid+secret,传入 `TokenCredential` 编译失败)。
> 托管模式下 SDK 内部自动调用本接口,调用者一般无需直接使用。典型使用者是自维护模式的调用者:自己取 token 后注入 `TokenCredential`。
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `getToken()` | 无 | `GetTokenResponse` | 标准 access_token 获取,含 accessToken、expiresIn |
| `getStableAccessToken(boolean forceRefresh)` | `forceRefresh`:是否强制刷新 | `GetTokenResponse` | 稳定版 access_token,长期有效,`false` 时微信尽量返回有效期内的既有 token |
```java
WxTokenAPI tokenAPI = new WxTokenAPI(config);
GetTokenResponse resp = tokenAPI.getToken();
if (resp.isSuccess()) {
credential.updateAccessToken(resp.getAccessToken()); // 注入自维护凭证
}
```
## 4.2 WxOauthAPI —— 网页授权
**作用**:公众号网页授权(OAuth2.0)全流程 + 小程序 code 换 session。**仅接受 `ApiConfig`**。
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `getOauthPageUrl(redirectUrl, scope, state)` | `redirectUrl` 回调地址;`scope` 作用域(`SNSAPI_BASE` 静默授权 / `SNSAPI_USERINFO` 弹确认框);`state` 透传参数 | `String` | 生成授权页 URL,用户在微信中打开即开始授权 |
| `getToken(code)` | `code`:回调地址中拿到的授权 code | `OauthGetTokenResponse` | code 换 token + openid,仅授权 openid 到此为止 |
| `refreshToken(refreshToken)` | `refreshToken`:getToken 返回值中的字段 | `OauthGetTokenResponse` | 刷新 token,返回全新 token 对象 |
| `getUserInfo(token, openid)` | `token`:网页授权 token;`openid`:用户 openid | `GetUserInfoResponse` | 获取用户详细信息(需 SNSAPI_USERINFO) |
| `validToken(token, openid)` | 同上 | `boolean` | 校验 token 是否合法有效 |
| `jscode2session(jsCode[, grantType])` | `jsCode`:小程序 wx.login 获得的 code | `JsCode2SessionResponse` | 小程序专用:code 换 openid + session_key |
```java
WxOauthAPI oauthAPI = new WxOauthAPI(config);
// 第一步:生成授权链接(拼进你的页面里)
String url = oauthAPI.getOauthPageUrl("https://your.domain/callback",
OauthScope.SNSAPI_USERINFO, "state123");
// 第二步:用户授权后回调带 code
OauthGetTokenResponse tokenResp = oauthAPI.getToken(code);
GetUserInfoResponse user = oauthAPI.getUserInfo(tokenResp.getAccessToken(), tokenResp.getOpenid());
```
## 4.3 WxJsAPI —— JS-SDK 签名
**作用**:计算网页调用微信 JS-SDK 所需签名。**接受 `JsApiTicketProvider`**(`ApiConfig` 或 `JsTicketCredential`)。纯本地运算,不发起 HTTP 请求。
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `getSignature(url)` | `url`:当前网页 URL,**不包含 # 及后面部分** | `GetSignatureResponse` | 简化版:随机数和时间戳自动生成(UUID / 当前秒) |
| `getSignature(nonceStr, timestame, url)` | 全部签名参数自控 | `GetSignatureResponse` | 完全控制版 |
返回对象含 `signature`、`nonceStr`、`timestamp`、`url`——前端 wx.config 需要的全部字段。
```java
WxJsAPI jsAPI = new WxJsAPI(config); // ApiConfig 自动管理 jsapi_ticket
GetSignatureResponse sign = jsAPI.getSignature("https://your.domain/page");
// 前端调用示例:
// wx.config({
// timestamp: sign.getTimestamp(),
// nonceStr: sign.getNonceStr(),
// signature: sign.getSignature(),
// ...
// });
```
## 4.4 WxJsTicketApi —— 获取 jsapi_ticket
**作用**:用 access_token 换取 jsapi_ticket。**接受 `AccessTokenProvider`**。
> 托管模式(`ApiConfig`)自动管理 ticket,无需调用本 API。典型使用者是自维护模式:拿 token 换 ticket 后注入 `JsTicketCredential`。
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `getJsTicket(jsApiType)` | `jsApiType`:`JsApiType.jsapi`(网页 JS-SDK)/ `JsApiType.wx_card`(卡券) | `JsTicketResponse` | 获取对应类型的 ticket |
## 4.5 WxMenuAPI —— 自定义菜单
**作用**:创建/查询/删除自定义菜单,支持个性化菜单(按标签、性别、地区等匹配不同菜单)。**接受 `AccessTokenProvider`**。
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `createMenu(Menu)` | `menu`:菜单对象,`button` 最多 3 个一级,每个最多 5 个二级;设置 `matchrule`(`Matchrule`)即为个性化菜单 | `ResultType` | 创建(普通/个性化)菜单 |
| `getMenu()` | 无 | `GetMenuResponse` | 获取通过接口创建的菜单 |
| `deleteMenu()` | 无 | `ResultType` | 删除所有菜单(含个性化菜单) |
| `deleteConditionalMenu(menuId)` | `menuId`:个性化菜单 ID | `ResultType` | 删除指定个性化菜单 |
| `tryMatchMenu(userId)` | `userId`:粉丝 openid 或微信号 | `GetMenuResponse` | 测试某用户能看到的个性化菜单 |
| `getCurrSelfMenuInfo()` | 无 | `GetCurrSelfMenuInfoResponse` | 获取当前菜单配置(含微信后台配置的菜单) |
```java
WxMenuAPI menuAPI = new WxMenuAPI(config);
Menu menu = new Menu();
MenuButton btn = new MenuButton();
btn.setType(MenuType.CLICK);
btn.setName("点我");
btn.setKey("BTN_HELLO");
menu.setButton(Collections.singletonList(btn));
menuAPI.createMenu(menu);
```
`MenuButton` 主要字段:`type`(`MenuType`:click / view / scancode_push / pic_photo_or_album / location_select / media_id / view_limited / miniprogram 等)、`name`、`key`、`url`、`appid`+`pagepath`(小程序跳转)、`mediaId`、`subButton`(二级菜单)。
## 4.6 WxCustomAPI —— 客服消息与客服账号
**作用**:向用户发送客服消息(48 小时内互动过才可发)、管理客服账号。**接受 `AccessTokenProvider`**。
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `sendCustomMessage(openid, message)` | `openid`:关注者 ID;`message`:`BaseMsg` 子类(支持全部消息类型) | `ResultType` | 发送客服消息(通用入口) |
| `sendCustomTextMessage / sendCustomImageMessage / sendCustomVoiceMessage / sendCustomVideoMessage / sendCustomMusicMessage / sendCustomNewsMessage` | 同上,消息类型固定 | `ResultType` | 类型化快捷入口 |
| `addCustomAccount(CustomAccount)` | `customAccount`:客服账号(accountName 昵称必填) | `ResultType` | 添加客服账号 |
| `updateCustomAccount(CustomAccount)` | 同上 | `ResultType` | 修改客服账号信息 |
| `deleteCustomAccount(accountName)` | `accountName`:完整客服账号名 | `ResultType` | 删除客服账号 |
| `uploadHeadImg(accountName, file)` | `file`:头像图片文件 | `ResultType` | 设置客服账号头像 |
| `getCustomAccountList()` | 无 | `GetCustomAccountsResponse` | 获取所有客服账号(含在线状态) |
```java
WxCustomAPI customAPI = new WxCustomAPI(config);
customAPI.sendCustomMessage("openid", new TextMsg("你好,请问有什么可以帮您?"));
```
## 4.7 WxUserAPI —— 用户管理
**作用**:关注者列表、用户信息、备注、分组、标签的增删改查。**接受 `AccessTokenProvider`**。
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `getUsers(nextOpenid)` | `nextOpenid`:拉取下一批的游标,首批传 null | `GetUsersResponse` | 获取关注者列表(openid 列表,每次最多 10000) |
| `getUserInfo(openid)` | `openid`:关注者 ID | `GetUserInfoResponse` | 获取用户信息(昵称、头像、性别、城市、关注时间等) |
| `getUserInfoList(userInfoList)` | `openid` 列表(最多 100) | `GetUserInfoListResponse` | 批量获取用户信息 |
| `setUserRemark(openid, remark)` | `remark`:备注内容 | `ResultType` | 设置用户备注 |
| `createGroup(name)` | `name`:分组名称 | `CreateGroupResponse` | 创建分组(含新分组 ID) |
| `getGroups()` | 无 | `GetGroupsResponse` | 获取所有分组 |
| `getGroupIdByOpenid(openid)` | 无 | `String` | 查询用户所在分组 ID |
| `updateGroup(groupid, name)` | `groupid` / 新名称 | `ResultType` | 修改分组名称 |
| `moveGroupUser(openid, toGroupid)` / `moveGroupUser(openids[], toGroupid)` | 用户 / 用户数组,目标分组 | `ResultType` | 移动用户到指定分组(数组版最多 50) |
| `deleteGroup(groupId)` | 无 | `ResultType` | 删除分组 |
| `batchTagsToUser(openidList, tagId)` | openid 列表,标签 ID | `ResultType` | 批量为用户打标签(每用户最多 3 个) |
| `batchDeleteTagsToUser(openidList, tagId)` | 同上 | `ResultType` | 批量为用户取消标签 |
## 4.8 WxTagAPI —— 标签管理
**作用**:用户标签的增删改查。**接受 `AccessTokenProvider`**。
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `create(tagName)` | `tagName`:标签名( UTF-8 ≤30 字) | `CreateTagResponse` | 创建标签(含新标签 ID) |
| `getAllTags()` | 无 | `GetAllTagsResponse` | 获取已创建的全部标签 |
| `updateTag(tagId, newTagName)` | 标签 ID / 新名称 | `ResultType` | 编辑标签 |
| `deleteTag(tagId)` | 标签 ID | `ResultType` | 删除标签 |
| `getUsersByTagId(tagId, nextOpenid)` | `nextOpenid`:翻页游标,首批传 null | `GetUsersResponse` | 获取标签下粉丝 |
## 4.9 WxMediaAPI —— 临时多媒体
**作用**:上传/下载临时素材(微信服务器保存 **3 天**)。**接受 `AccessTokenProvider`**。
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `uploadMedia(type, file)` | `type`:`MediaType`(image / voice / video / thumb);`file`:文件 | `UploadMediaResponse` | 上传临时素材,返回 mediaId |
| `uploadNews(articles)` | `articles`:`Article` 列表 | `UploadMediaResponse` | 上传群发图文素材 |
| `uploadImg(file)` | `file`:图片文件 | `UploadImgResponse` | 上传群发消息中的图片,返回图片 URL(用于图文正文) |
| `downloadMedia(mediaId)` | `mediaId`:素材 ID | `DownloadMediaResponse` | 下载素材(通过 `writeTo(OutputStream)` 输出) |
## 4.10 WxMaterialAPI —— 永久素材
**作用**:永久素材的上传/下载/列表/删除(图片上限 5000,其他类型 1000)。**接受 `AccessTokenProvider`**。
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `uploadMaterialFile(file)` | `file`:素材文件 | `UploadMaterialResponse` | 上传永久素材(图片/语音、缩略图) |
| `uploadMaterialFile(file, title, introduction)` | 同上 + 标题、描述 | `UploadMaterialResponse` | 上传永久视频素材 |
| `uploadMaterialNews(articles)` | `articles`:`Article` 列表 | `UploadMaterialResponse` | 上传永久图文素材 |
| `updateMaterialNews(mediaId, index, article)` | `index`:多图文中文章位置(首篇为 0) | `UploadMaterialResponse` | 更新图文素材中的单篇文章 |
| `downloadMaterial(mediaId, type)` | `type`:`MaterialType`(image / voice / video / thumb / news) | `DownloadMaterialResponse` | 下载永久素材 |
| `countMaterial()` | 无 | `GetMaterialTotalCountResponse` | 获取各类型素材总数 |
| `batchGetMaterial(type, offset, count)` | `offset`:偏移;`count`:1–20 | `GetMaterialListResponse` | 分页获取素材列表 |
| `deleteMaterial(mediaId)` | 无 | `ResultType` | 删除永久素材 |
## 4.11 WxMassMessageAPI —— 群发
**作用**:按分组/全部用户群发消息。**接受 `AccessTokenProvider`**。
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `sendAll(message, isToAll, groupId)` | `message`:`MpNewsMsg`(图文)/ `TextMsg` / `VoiceMsg` / `ImageMsg` / `VideoMsg`;`isToAll`:是否发给全部用户;`groupId`:分组 ID(isToAll 为 false 时有效,可 null) | `GetSendMessageResponse` | 群发消息,返回 msgId(用于撤回与统计) |
```java
WxMassMessageAPI massAPI = new WxMassMessageAPI(config);
GetSendMessageResponse resp = massAPI.sendAll(new TextMsg("群发内容"), false, groupId);
```
## 4.12 WxQrcodeAPI —— 带参二维码
**作用**:创建带场景值的二维码(扫码后触发 `handleQrCodeEvent`)。**接受 `AccessTokenProvider`**。
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `createQrcode(actionName, sceneId, expireSeconds)` | `actionName`:`QrcodeType.QR_SCENE`(临时)/ `QR_LIMIT_SCENE`(永久);`sceneId`:场景值(临时为非 0 整型,永久 1–100000);`expireSeconds`:有效期秒数,最大 2592000(30 天),不填默认 30 秒 | `QrcodeResponse` | 创建整型场景值二维码,返回 ticket 与二维码图片 URL |
| `createQrcode(actionName, sceneId, sceneStr, expireSeconds)` | `sceneStr`:字符串场景值(1–64 字符,仅 `QR_LIMIT_STR_SCENE` 永久二维码支持) | `QrcodeResponse` | 创建字符串场景值二维码 |
## 4.13 WxTemplateMsgAPI —— 模板消息
**作用**:设置行业、添加模板、发送模板消息。**接受 `AccessTokenProvider`**。
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `setIndustry(industry)` | `industry`:`Industry`(industryId1 / industryId2 行业代码) | `ResultType` | 设置所属行业(每月可修改一次) |
| `addTemplate(shortTemplateId)` | `shortTemplateId`:模板库中模板的短 ID | `AddTemplateResponse` | 添加到我的模板,返回模板 ID |
| `send(TemplateMsg)` | `msg`:`TemplateMsg`(touser、templateId、url、data) | `SendTemplateResponse` | 发送模板消息,返回 msgId |
| `getAllPrivateTemplate()` | 无 | `PrivateTemplatesResponse` | 获取已添加的全部私有模板 |
```java
WxTemplateMsgAPI templateAPI = new WxTemplateMsgAPI(config);
TemplateMsg msg = new TemplateMsg();
msg.setTouser("openid");
msg.setTemplateId("templateId");
msg.addData("keyword1", "订单已发货");
SendTemplateResponse resp = templateAPI.send(msg);
```
## 4.14 WxDataCubeAPI —— 数据统计
**作用**:获取公众号运营数据(用户、图文、消息、接口四大数据分析)。**接受 `AccessTokenProvider`**。
| 方法 | 日期跨度 | 返回 | 数据内容 |
|---|---|---|---|
| `getUserSummary(begin, end)` | 最大 7 天 | `GetUserSummaryResponse` | 用户增减数据(新关注/取消关注/净增) |
| `getUserCumulate(begin, end)` | 最大 7 天 | `GetUserCumulateResponse` | 累计用户数据 |
| `getArticleSummary(day)` | 单日 | `GetArticleSummaryResponse` | 图文群发每日数据(阅读、分享、收藏) |
| `getArticleTotal(day)` | 单日 | `GetArticleTotalResponse` | 图文群发总数据(含全部日期明细) |
| `getUserRead(begin, end)` | 最大 3 天 | `GetUserReadResponse` | 图文统计数据(阅读人数/次数) |
| `getUserReadHour(day)` | 单日 | `GetUserReadHourResponse` | 图文统计分时数据 |
| `getUserShare(begin, end)` | 最大 7 天 | `GetUserShareResponse` | 图文分享转发数据 |
| `getUserShareHour(day)` | 单日 | `GetUserShareHourResponse` | 图文分享转发分时数据 |
| `getUpstreamMsg(begin, end)` | 最大 7 天 | `GetUpstreamMsgResponse` | 消息发送概况数据 |
| `getUpstreamMsgHour(day)` | 单日 | `GetUpstreamMsgHourResponse` | 消息发送分时数据 |
| `getUpstreamMsgWeek(begin, end)` | 最大 30 天 | `GetUpstreamMsgWeekResponse` | 消息发送周数据 |
| `getUpstreamMsgMonth(begin, end)` | 最大 30 天 | `GetUpstreamMsgMonthResponse` | 消息发送月数据 |
| `getUpstreamMsgDist(begin, end)` | 最大 15 天 | `GetUpstreamMsgDistResponse` | 消息发送分布数据 |
| `getUpstreamMsgDistWeek(begin, end)` | 最大 30 天 | `GetUpstreamMsgDistWeekResponse` | 消息发送分布周数据 |
| `getUpstreamMsgDistMonth(begin, end)` | 最大 30 天 | `GetUpstreamMsgDistMonthResponse` | 消息发送分布月数据 |
| `getInterfaceSummary(begin, end)` | 最大 30 天 | `GetInterfaceSummaryResponse` | 接口调用分析数据 |
| `getInterfaceSummaryHour(day)` | 单日 | `GetInterfaceSummaryHourResponse` | 接口调用分时数据 |
## 4.15 WxSystemAPI —— 系统
**作用**:获取微信服务器 IP、长短链接转换。**接受 `AccessTokenProvider`**。
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `getCallbackIP()` | 无 | `List` | 微信服务器 IP 列表(用于安全校验) |
| `getShortUrl(longUrl)` | `longUrl`:需要转换的长链接 | `GetShortUrlResponse` | 长链接转短链接 |
---
# 5. 使用手册:小程序 API
小程序接口与公众号接口共用同一套凭证(`ApiConfig` / `TokenCredential`),位于 `com.fastweixin.mina.api` 包。
## 5.1 WxMinaCodeApi —— 小程序码
**作用**:生成小程序码/小程序二维码。**接受 `AccessTokenProvider`**。
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `getWxaCode(param)` | `param`:`GetWxaCodeParam`(path、width、autoColor、lineColor 等) | `FileResponse` | 接口①:生成小程序码,永久有效。**①+③ 共限 100,000 个** |
| `getWxaCodeUnlimit(param)` | `param`:`GetWxacodeUnlimitParam`(scene、page、checkPath 等) | `FileResponse` | 接口②:生成小程序码,永久有效,**数量暂无限制**(scene 参数经小程序内自行解析) |
| `createWxaQrcode(param)` | 同接口① | `FileResponse` | 接口③:生成普通小程序二维码,永久有效。**①+③ 共限 100,000 个** |
`FileResponse` 为文件流响应,通过 `writeTo(OutputStream)` 输出图片。
## 5.2 WxMinaTemplateMsgAPI —— 模板消息(已废弃接口)
**作用**:小程序模板消息的添加与发送(微信已停止模板消息能力,新代码请用订阅消息)。**接受 `AccessTokenProvider`**。
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `addTemplate(shortTemplateId)` | 模板短 ID | `AddTemplateResponse` | 添加模板 |
| `send(TemplateMsg)` | `msg`:touser、templateId、page、formId、data | `SendTemplateResponse` | 发送模板消息 |
## 5.3 WxMinaSubscribeMsgAPI —— 订阅消息
**作用**:发送小程序订阅消息。**接受 `AccessTokenProvider`**。
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `send(SubscribeMsg)` | `msg`:touser、templateId、page、data | `BaseResponse` | 发送订阅消息 |
## 5.4 WxPhoneAPI —— 获取手机号
**作用**:通过手机号授权 code 获取用户手机号。**接受 `AccessTokenProvider`**。
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `getPhoneNumber(phoneCode)` | `phoneCode`:前端 `getPhoneNumber` 事件回调中获得的 code | `GetPhoneNumberResponse` | 返回手机号信息(`getPhoneInfo()` 取 phoneNumber 等字段) |
另:`WxOauthAPI.jscode2session(jsCode)`(见 4.2)用于小程序登录换取 openid / session_key。
---
# 6. 使用手册:企业微信 API
企业微信(企业号)体系位于 `com.fastweixin.company.api` 包,凭证体系独立于公众号,编译期互相隔离:
- 托管模式:`new QYAPIConfig(corpId, corpSecret)`(token 自动管理);
- 自维护模式:`new QyTokenCredential(accessToken)` + `updateAccessToken()`;
- 所有企业微信 API 构造参数为 `QyAccessTokenProvider`,其中 `QYOauthAPI` 需要 `QYAPIConfig`(要用 corpId 拼 OAuth 链接)。
返回值基类同样是 `BaseResponse`,错误码枚举为 `QYResultType`。
## 6.1 QYUserAPI —— 通讯录用户管理
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `create(QYUser)` / `update(QYUser)` | `QYUser`(userId、name、department、mobile、email……) | `QYResultType` | 创建 / 更新成员 |
| `delete(userId)` / `batchdelete(userIds[])` | 用户 ID | `QYResultType` | 删除 / 批量删除成员 |
| `get(userId)` | 用户 ID | `GetQYUserInfoResponse` | 获取成员完整信息 |
| `simpleList(departmentId, isLoop, status)` | `isLoop`:是否递归子部门;`status`:0 全部 / 1 已关注 / 2 禁用 / 4 未关注(可叠加) | `GetQYUserInfo4DepartmentResponse` | 部门成员摘要(仅 userid + name) |
| `getList(departmentId, isLoop, status)` | 同上 | `GetQYUserInfo4DepartmentResponse` | 部门成员完整信息 |
| `invite(userid)` | 用户 ID | `GetQYUserInviteResponse` | 邀请成员关注(返回 1 微信邀请 / 2 邮件邀请) |
| `getOauthUserInfo(code)` | OAuth code | `GetOauthUserInfoResponse` | code 换成员身份(UserId 或 OpenId + DeviceId) |
## 6.2 QYDepartmentAPI —— 部门管理
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `getList(parentId)` | `parentId`:父部门 ID,null 为顶级 | `GetDepartmentListResponse` | 获取部门列表 |
| `create(QYDepartment)` | `QYDepartment`(name、parentId、order) | `CreateDepartmentResponse` | 创建部门,返回新部门 ID |
| `update(QYDepartment)` | 同上(含 id) | `QYResultType` | 更新部门 |
| `delete(id)` | 部门 ID | `QYResultType` | 删除部门(有成员/子部门时微信会拒绝) |
## 6.3 QYAgentAPI —— 应用管理
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `getAll()` | 无 | `GetQYAgentListResponse` | 获取全部应用列表 |
| `getInfo(agentId)` | 应用 ID | `GetQYAgentInfoResponse` | 获取应用信息 |
| `create(QYAgent, mediaId)` | `QYAgent` + logo 素材 ID | `QYResultType` | 设置应用信息(旧接口,建议用 update) |
| `update(params)` | `Map`:待更新的应用属性 | `QYResultType` | 设置应用信息(新接口) |
## 6.4 QYMessageAPI —— 应用消息推送
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `send(QYBaseMsg)` | `QYBaseMsg` 子类:文本、图片、语音、视频、文件、图文、Markdown 等(toUser / toParty / toTag + agentId) | `GetQYSendMessageResponse` | 向成员/部门/标签推送应用消息,返回无效用户/部门/标签列表 |
## 6.5 QYTagAPI —— 标签管理
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `create(QYTag)` | `QYTag`(tagname 必填,tagid 不填自动递增) | `CreateTagResponse` | 创建标签 |
| `delete(tagid)` | 标签 ID | `QYResultType` | 删除标签 |
| `get(tagid)` | 标签 ID | `GetTagInfoResponse` | 获取标签内成员/部门 |
| `addTagUsers(tagid, users, partys)` | 用户 ID 列表(≤1000)/ 部门 ID 列表(≤100),不能同时为空 | `AddTagUsersResponse` | 增加标签成员,返回非法成员 |
| `delTagUsers(tagid, users, partys)` | 同上 | `DelTagUsersResponse` | 删除标签成员 |
| `list()` | 无 | `GetTagListResponse` | 获取标签列表 |
## 6.6 QYMenuAPI —— 企业微信菜单
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `create(QYMenu, agentId)` | `menu` + 应用 ID | `QYResultType` | 创建应用菜单 |
| `list(agentId)` | 应用 ID | `GetQYMenuResponse` | 获取应用菜单 |
| `delete(agentId)` | 应用 ID | `QYResultType` | 删除应用菜单 |
## 6.7 QYMediaAPI —— 素材管理
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `upload(type, file)` | `MediaType` + 文件 | `UploadMediaResponse` | 上传媒体文件 |
| `download(mediaId)` | 素材 ID | `DownloadMediaResponse` | 下载媒体文件(`writeTo(OutputStream)` 输出) |
## 6.8 QYOauthAPI —— 企业微信 OAuth
**仅接受 `QYAPIConfig`**。
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `getOauthPageUrl(redirectUrl, scope, state)` | 回调地址 / 作用域 / 透传参数 | `String` | 生成企业微信 OAuth 授权页链接 |
(code 换用户信息用 `QYUserAPI.getOauthUserInfo(code)`,见 6.1。)
## 6.9 企业微信消息服务器
`QYWeixinControllerSupport` / `QYWeixinServletSupport` / `QYWeixinSupport` 的用法与公众号的消息服务器(第 3 章)完全一致,仅基类不同。
---
# 7. 使用手册:开放平台 API
开放平台(第三方平台代公众号运营)位于 `com.fastweixin.open.api` 包。凭证类 `OpenApiConfig` 较特殊:
- 托管模式:`new OpenApiConfig(componentAppid, componentSecret)`——用 `getAccessToken(component_verify_ticket)` 换取并自动维护 component_access_token;
- 自维护模式:`new OpenApiConfig(componentAppid, "")` + `updateComponentAccessToken(token)`——开放平台接口的请求体均需 component_appid,故自维护模式也必须携带 appid(不能使用 `TokenCredential`)。
## 7.1 OpenComponentApi —— 第三方平台授权
所有方法均在构造时指定凭证,token 不再作为方法参数传递。
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| `getAccessToken(component_verify_ticket)` | `component_verify_ticket`:微信每 10 分钟推送的验证票据(从消息回调中获取) | `ComponentAccessTokenResp` | 获取 component_access_token(托管模式下成功后自动写入凭证) |
| `getPreAuthCode()` | 无 | `PreAuthCodeResp` | 获取预授权码 |
| `getAuthUrl(pre_auth_code, redirect_uri)` | 预授权码 + 回调地址 | `String` | 拼接公众号授权第三方平台的链接 |
| `getAuthInfo(authorization_code)` | 授权回调得到的 authorization_code | `AuthInfoResp` | 获取公众号授权信息(授权方 token、授权功能列表) |
| `getAuthorizerInfo(authorizer_appid)` | 授权方 appid | `AuthorizerInfoResp` | 获取授权方公众号基本信息(昵称、类型、认证情况等) |
| `getAuthorizerToken(authorizer_appid, authorizer_refresh_token)` | 授权方 appid + 刷新 token | `AuthorizerTokenResp` | 刷新授权方 token |
```java
OpenApiConfig config = new OpenApiConfig(componentAppid, componentSecret);
OpenComponentApi api = new OpenComponentApi(config);
// 换取 component_access_token(用消息回调收到的 ticket)
api.getAccessToken(componentVerifyTicket);
// 发起授权
PreAuthCodeResp preAuth = api.getPreAuthCode();
String authUrl = api.getAuthUrl(preAuth.getPre_auth_code(), "https://your.domain/callback");
// 授权回调后换取授权方信息
AuthInfoResp authInfo = api.getAuthInfo(authorizationCode);
```
---
# 8. 使用手册:微信支付
## 8.1 V2(XML 签名体系)
支付类 API **不接入凭证层**,使用微信支付商户号体系,无参构造:
| API | 方法 | 说明 |
|---|---|---|
| `WxPayApi` | `unifiedOrder(UnifiedOrder)` | 统一下单(返回 prepay_id / code_url) |
| | `queryOrder(OrderQuery, key)` | 订单查询 |
| | `refund(PayRefundParam, certFile, key)` | 退款(需商户证书文件) |
| | `queryRefund(RefundQueryParam, key)` | 退款查询 |
| `WxRedPackApi` | `sendRedPack(SendRedPackParam, certFile)` | 发送现金红包(需证书) |
| `WxTransferPayApi` | `transferPay(TransferPayParam, certFile)` | 企业付款到零钱(需证书) |
| | `batchTransferPay(BatchTransferPayParam, certFile)` | 批量企业付款(需证书) |
| `WxPayBankApi` | `pay_bank(PayBankParam, certFile)` | 企业付款到银行卡(需证书) |
| | `getPublicKey(GetPublicParam, certFile)` | 获取 RSA 公钥(付款到银行卡前必须调用) |
| | `queryBankResult(QueryPayBankResultParam, certFile)` | 查询付款到银行卡结果 |
`key` 为商户 API 密钥;`certFile` 为商户证书 p12 文件。
## 8.2 V3(SHA256withRSA 签名体系)
位于 `com.fastweixin.v3.api` 包,使用 `WxPayAppConfig(mchId, certPath)` 构造(商户号 + 证书路径)。
| API | 方法 | 说明 |
|---|---|---|
| `WxPayApi` | `queryOrderByTransactionId(transactionId)` / `queryOrderByOutTradeNo(outTradeNo)` | 查询订单 |
| | `refund(RefundParam)` | 发起退款 |
| | `queryRefundOrder(outRefundNo)` | 查询退款单 |
| `WxTransferBatchApi` | `batchTransfer(BatchTransferPayParam)` | 批量转账到零钱 |
| | `queryBatchByBatchId(batchId, param)` / `queryBatchByOutBatchNo(outBatchNo, param)` | 查询批次(微信批次号 / 商户批次单号) |
| | `queryBatchDetailByDetailId(batchId, detailId)` / `queryBatchDetailByOutDetailNo(outBatchNo, outDetailNo)` | 查询批次明细 |
| `WxPayCertApi` | `downloadLatestCertificates(savePath, forceOverride)` | 下载最新平台证书到本地 |
| | `getCertificates()` | 获取平台证书(CertificateResponse) |
| `WxPayV3Api` | `httpGet(url)` / `httpPost(url, body)` / `httpRequest(method, url, body)` | 带签名的基础请求入口(自定义 V3 接口时使用) |
---
# 9. 统一返回值与异常处理
## 9.1 BaseResponse
所有响应对象继承 `BaseResponse`:
| 方法 | 说明 |
|---|---|
| `isSuccess()` | 调用成功(errcode 为成功码) |
| `isFailed()` | 调用失败 |
| `getErrcode()` / `getErrmsg()` | 微信返回的错误码与描述 |
## 9.2 ResultType / QYResultType
仅返回成功/失败状态的接口直接返回 `ResultType`(公众号体系)或 `QYResultType`(企业微信体系),枚举值即微信官方错误码的语义化映射,`getCode()` / `getDescription()` 可取得原始错误码与描述。
## 9.3 WeixinException(3.0.0 行为变化)
以下情况 SDK 会在**请求发出前**抛出 `WeixinException`,消息自解释(写明缺什么、怎么办):
- 自维护凭证尚未设置值(如 `TokenCredential` 未调用 `updateAccessToken()`);
- 凭证类型与接口不匹配(如拿 `TokenCredential` 调需要 appid+secret 的接口——多数情况这在编译期已被拦截,此处为兜底);
- 托管模式下 appid / secret 错误,首次调用即报错(不再是静默的 errcode 41001)。
请在调用处按需捕获。**凭证缺失是编程错误,必须炸出来,不能与网络错误混淆。**
---
# 10. 版本升级
版本变更记录与迁移指引见 [update.md](update.md)。3.0.0 为破坏性版本(凭证体系重构),2.x 用户升级前请务必阅读其中的迁移表。