微信公众号
2025/6/15大约 7 分钟
微信公众号
系统提供完整的微信公众号接入与管理能力,支持多公众号绑定、消息接收/回复、素材管理、菜单管理、模板消息、微信支付等功能。
功能概览
| 模块 | 功能 | 说明 |
|---|---|---|
| 公众号账户 | 多账号管理 | 绑定多个公众号,支持明文/兼容/加密三种消息模式 |
| 消息管理 | 收发记录 | 完整的消息收发记录,支持会话视图查看 |
| 自动回复 | 关键词/关注回复 | 支持文本、图片、图文、音乐等多种回复类型 |
| 素材管理 | 临时/永久素材 | 上传、同步、本地存储,支持图片/语音/视频/图文 |
| 菜单管理 | 自定义菜单 | 可视化菜单编辑,一键发布/同步/删除 |
| 用户管理 | 粉丝信息 | 记录关注/取关、互动时间、消息计数 |
| 模板消息 | 行业模板推送 | 从微信同步模板,本地发送,记录发送日志 |
| 微信支付 | JSAPI/Native | 创建订单、查询、关闭、退款,回调通知处理 |
数据库表结构
所有微信相关表均使用 雪花 ID(Snowflake ID) 作为主键,取代自增 ID,确保分布式环境下的 ID 唯一性。
wx_accounts — 公众号账户(主表)
├── wx_auto_replies — 自动回复规则
├── wx_materials — 素材库
├── wx_menus — 自定义菜单
├── wx_messages — 消息记录
├── wx_users — 粉丝用户
├── wx_templates — 模板消息
├── wx_template_logs— 模板发送日志
├── wx_pay_orders — 支付订单
└── wx_pay_refunds — 退款记录wx_accounts(公众号账户)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | i64 (Snowflake) | 主键 |
| app_id | String (Unique) | 公众号 AppID |
| app_secret | String | 公众号 AppSecret |
| account_name | String | 账户名称 |
| account_type | i8 | 账户类型 |
| original_id | String | 原始 ID(gh_xxx) |
| wechat_id | String | 微信号 |
| status | i8 | 状态 |
| message_mode | i8 | 消息模式:0=明文 1=兼容 2=加密 |
| access_token | String | 缓存的 AccessToken |
| token_expires_at | DateTime | Token 过期时间 |
| server_url | String | 回调服务器 URL |
| token | String | 消息校验 Token |
| encoding_aes_key | String | 消息加解密密钥 |
wx_messages(消息记录)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | i64 (Snowflake) | 主键 |
| account_id | i64 (FK) | 所属公众号 |
| openid | String | 用户 OpenID |
| msg_id | i64 | 微信消息 ID |
| msg_type | String | 消息类型:text/image/voice/video/event 等 |
| direction | i8 | 方向:0=回复 1=收到 |
| content | Text | 文本内容 |
| pic_url | String | 图片 URL(异步下载到本地) |
| event_type | String | 事件类型:subscribe/unsubscribe/CLICK 等 |
| event_key | String | 事件 Key |
| is_auto_reply | i8 | 是否自动回复 |
wx_auto_replies(自动回复规则)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | i64 (Snowflake) | 主键 |
| account_id | i64 (FK) | 所属公众号 |
| reply_type | i8 | 规则类型:1=关注回复 2=关键词回复 |
| keyword | String | 匹配关键词 |
| match_type | i8 | 匹配方式:1=完全匹配 2=包含匹配 |
| message_type | String | 回复类型:text/image/news/music |
| content | Text | 回复文本内容 |
| media_id | String | 回复素材 media_id |
| priority | i32 | 优先级(数值越高越优先) |
| status | i8 | 状态:0=禁用 1=启用 |
wx_materials(素材库)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | i64 (Snowflake) | 主键 |
| account_id | i64 (FK) | 所属公众号 |
| media_type | String | 素材类型:image/voice/video/thumb/news |
| media_id | String | 微信素材 ID |
| name | String | 文件名称 |
| url | String | 微信服务器 URL |
| local_path | String | 本地存储路径 |
| file_size | i64 | 文件大小(字节) |
| width / height | i32 | 图片尺寸 |
| is_permanent | i8 | 0=临时素材 1=永久素材 |
| sync_status | i8 | 同步状态:0=未同步 1=已同步 |
wx_menus(自定义菜单)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | i64 (Snowflake) | 主键 |
| account_id | i64 (FK) | 所属公众号 |
| parent_id | i64 | 父菜单 ID(二级菜单) |
| menu_name | String | 菜单名称 |
| menu_type | String | 菜单类型:click/view/scancode_push 等 |
| menu_key | String | 菜单 Key 值 |
| url | String | 跳转 URL |
| media_id | String | 素材 media_id |
| appid | String | 小程序 appid |
| pagepath | String | 小程序页面路径 |
| sort_order | i32 | 排序 |
wx_users(粉丝用户)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | i64 (Snowflake) | 主键 |
| account_id | i64 (FK) | 所属公众号 |
| openid | String | 用户 OpenID |
| unionid | String | UnionID |
| nickname | String | 昵称 |
| headimgurl | String | 头像 |
| subscribe_status | i8 | 关注状态:0=未关注 1=已关注 |
| subscribe_time | DateTime | 关注时间 |
| unsubscribe_time | DateTime | 取关时间 |
| last_interact_time | DateTime | 最后互动时间 |
| message_count | i32 | 消息计数 |
wx_templates(模板消息)& wx_template_logs(发送日志)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | i64 (Snowflake) | 主键 |
| account_id | i64 (FK) | 所属公众号 |
| template_id | String | 微信模板 ID |
| title | String | 模板标题 |
| content | Text | 模板内容 |
| status | i8 | 状态 |
wx_pay_orders(支付订单)& wx_pay_refunds(退款记录)
| 字段 | 类型 | 说明 |
|---|---|---|
| id | i64 (Snowflake) | 主键 |
| account_id | i64 (FK) | 所属公众号 |
| out_trade_no | String | 商户订单号 |
| openid | String | 付款用户 OpenID |
| total_fee | i64 | 金额(分) |
| trade_state | String | 交易状态 |
| prepay_id | String | 预支付 ID |
| code_url | String | 二维码链接(Native 支付) |
API 接口
所有接口均需 JWT 认证,微信回调接口除外。
需认证的接口
| 路径 | 方法 | 说明 |
|---|---|---|
/wechat/wxaccounts/list | GET | 获取公众号列表 |
/wechat/wxaccounts/add | POST | 添加公众号 |
/wechat/wxaccounts/edit | PUT | 编辑公众号 |
/wechat/wxaccounts/del | DELETE | 删除公众号 |
/wechat/wxautoreplies/list | GET | 获取自动回复列表 |
/wechat/wxautoreplies/add | POST | 添加自动回复 |
/wechat/wxautoreplies/edit | PUT | 编辑自动回复 |
/wechat/wxautoreplies/del | DELETE | 删除自动回复 |
/wechat/wxmaterials/list | GET | 获取素材列表 |
/wechat/wxmaterials/add | POST | 添加素材 |
/wechat/wxmaterials/edit | PUT | 编辑素材 |
/wechat/wxmaterials/del | DELETE | 删除素材 |
/wechat/wxmaterials/upload_temp_media | POST | 上传临时素材到微信 |
/wechat/wxmaterials/upload_permanent_media | POST | 上传永久素材到微信 |
/wechat/wxmaterials/upload_news | POST | 上传永久图文素材 |
/wechat/wxmaterials/sync_materials | POST | 从微信同步素材到本地 |
/wechat/wxmaterials/material_count | POST | 获取微信素材计数 |
/wechat/wxmaterials/delete_remote_media | POST | 删除微信服务器永久素材 |
/wechat/wxmaterials/upload_file | POST | 上传文件到服务器本地 |
/wechat/wxmenus/list | GET | 获取菜单列表 |
/wechat/wxmenus/add | POST | 添加菜单 |
/wechat/wxmenus/edit | PUT | 编辑菜单 |
/wechat/wxmenus/del | DELETE | 删除菜单 |
/wechat/wxmenus/pull_menu | POST | 发布菜单到微信 |
/wechat/wxmenus/sync_menu | POST | 从微信同步菜单到本地 |
/wechat/wxmenus/delete_remote_menu | POST | 删除微信服务器自定义菜单 |
/wechat/wxmessages/list | GET | 获取消息列表 |
/wechat/wxmessages/add | POST | 添加消息(客服消息) |
/wechat/wxmessages/edit | PUT | 编辑消息 |
/wechat/wxmessages/del | DELETE | 删除消息 |
/wechat/wxmessages/conversation | GET | 获取会话消息列表 |
/wechat/wxmessages/reply | POST | 回复消息 |
/wechat/wxusers/list | GET | 获取粉丝列表 |
/wechat/wxusers/add | POST | 添加粉丝 |
/wechat/wxusers/edit | PUT | 编辑粉丝 |
/wechat/wxusers/del | DELETE | 删除粉丝 |
/wechat/wxtemplates/list | GET | 获取模板列表 |
/wechat/wxtemplates/add | POST | 添加模板 |
/wechat/wxtemplates/edit | PUT | 编辑模板 |
/wechat/wxtemplates/del | DELETE | 删除模板 |
/wechat/wxtemplates/sync | POST | 从微信服务器同步模板 |
/wechat/wxtemplates/send | POST | 发送模板消息 |
/wechat/wxtemplates/logs | GET | 获取模板发送日志 |
/wechat/wxpay/orders | GET | 获取支付订单列表 |
/wechat/wxpay/refunds | GET | 获取退款列表 |
/wechat/wxpay/create_order | POST | 创建支付订单 |
/wechat/wxpay/query_order | POST | 查询订单状态 |
/wechat/wxpay/close_order | POST | 关闭订单 |
/wechat/wxpay/refund | POST | 申请退款 |
免认证的回调接口(微信服务器调用)
| 路径 | 方法 | 说明 |
|---|---|---|
/wechat/official_account/callback | GET | 微信服务器验证 |
/wechat/official_account/callback | POST | 微信消息/事件回调 |
/wechat/wxpay/notify/{account_id} | POST | 微信支付回调通知 |
消息处理流程
微信服务器
│ POST /wechat/official_account/callback
▼
┌─────────────────────────────┐
│ 1. 签名验证 │
│ verify_request_signature │
├─────────────────────────────┤
│ 2. 消息解密(加密模式) │
│ WechatCrypto::decrypt │
├─────────────────────────────┤
│ 3. 存储收到的消息 │
│ WxMessagesModel::add │
│ direction = 1 (收到) │
├─────────────────────────────┤
│ 4. 图片消息异步下载 │
│ WxImageDownloadWorker │
│ (mmbiz.qpic.cn → 本地) │
├─────────────────────────────┤
│ 5. 消息处理 & 自动回复 │
│ ┌─ 文本消息 → 关键词匹配 │
│ ├─ 关注事件 → 关注回复 │
│ ├─ 点击事件 → 事件回复 │
│ └─ 取关事件 → 更新状态 │
├─────────────────────────────┤
│ 6. 存储回复消息 │
│ WxMessagesModel::add │
│ direction = 0 (回复) │
└─────────────────────────────┘
│ XML 回复
▼
微信服务器自动回复机制
系统支持三种自动回复类型,按优先级从高到低处理:
关键词回复(reply_type = 2)
- 按优先级降序匹配
- 支持完全匹配(match_type = 1)和包含匹配(match_type = 2)
- 支持回复类型:文本、图片、图文、音乐
关注回复(reply_type = 1)
- 用户关注公众号时自动触发
- 同时创建/更新粉丝用户记录
默认回复
- 以上规则均未命中时返回默认文本
消息加解密支持
系统支持三种消息模式:
| 模式 | message_mode | 说明 |
|---|---|---|
| 明文模式 | 0 | 消息不加密,直接解析 XML |
| 兼容模式 | 1 | 明文解析(兼容加密消息) |
| 安全模式 | 2 | 使用 AES 加解密,需配置 EncodingAESKey |
前端页面
| 页面路径 | 功能 |
|---|---|
/wechat/wxaccounts | 公众号账户管理 |
/wechat/wxautoreplies | 自动回复规则配置 |
/wechat/wxmaterials | 素材管理(上传/同步/预览) |
/wechat/wxmenus | 自定义菜单编辑器 |
/wechat/wxmessages | 消息记录与会话 |
/wechat/wxusers | 粉丝用户管理 |
技术要点
雪花 ID
微信模块的所有表均使用雪花 ID 替代自增 ID:
- 分布式唯一:多实例部署不会 ID 冲突
- 不可猜测:避免通过 ID 遍历数据的安全风险
- 时间排序:ID 本身包含时间信息,天然有序
实现方式:SeaORM Entity 中设置 auto_increment = false,Model 层 add 方法插入时使用 GID() 生成 ID。
确保中文内容(消息、模板、日志等)正确存储和检索。
图片异步下载
微信图片消息中的图片 URL(mmbiz.qpic.cn)有时效限制,系统通过 WxImageDownloadWorker 异步下载到本地:
收到图片消息 → 记录消息 → 入队下载任务 → Worker 下载图片 → 更新 local_path