# 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 用户升级前请务必阅读其中的迁移表。