diff --git a/clients/java/wechat-ferry-mvn/CHANGELOG.md b/clients/java/wechat-ferry-mvn/CHANGELOG.md index cf6c553..e5a9227 100644 --- a/clients/java/wechat-ferry-mvn/CHANGELOG.md +++ b/clients/java/wechat-ferry-mvn/CHANGELOG.md @@ -1,31 +1,81 @@ ## v39.3.3 +### 版本列表 + +下载地址:[v39.3.3](https://github.com/lich0821/WeChatFerry/releases/tag/v39.3.3) + +| 名称 | 版本 | 文件名 | +|-----------------|-----------|---------------------------| +| 微信客户端 | 3.9.11.25 | WeChatSetup-3.9.11.25.exe | +| WeChatFerry-SDK | 39.3.3 | v39.3.3.zip | + ### 功能列表 -| 接口名 | 地址 | 是否支持 | 备注 | -|----------------|-------------------|------|-------------------| -| 查询登录状态 | /loginStatus | √ | 已测试 | -| 获取登录微信内部识别号UID | /loginWeChatUid | √ | 已测试 | -| 获取登录微信信息 | /loginWeChatInfo | √ | 已测试 | -| 获取消息类型列表 | /list/msgType | √ | 已测试 | -| 获取联系人列表 | /list/contacts | √ | 已测试 | -| 获取数据库表名称列表 | /list/dbTableName | √ | 已测试 | -| 获取指定数据库中的表列表 | /list/dbTable | √ | 已测试 | -| 执行数据库查询SQL | /exec/dbQuerySql | √ | 已测试 | -| 查询群成员 | /list/groupMember | √ | 已测试 | -| 发送消息汇总入口 | /send/msgMaster | x | 预留 | -| 发送文本消息 | /send/textMsg | x | 该版本不支持 | -| 发送富文本消息 | /send/richTextMsg | x | 缩略图参数需要为空,否则会发送失败 | -| 发送XML消息 | /send/xmlMsg | ? | 待测试 | -| 发送图片消息 | /send/imageMsg | √ | 已测试 | -| 发送表情消息 | /send/emojiMsg | x | 该版本不支持 | -| 发送文件消息 | /send/fileMsg | x | 该版本不支持 | -| 拍一拍群友 | /patOnePat | √ | 已测试 | +| 接口名 | 地址 | 是否支持 | 备注 | +|----------------|------------------------|------|-------------------| +| 查询登录状态 | /loginStatus | ✔️ | 已测试 | +| 获取登录微信内部识别号UID | /loginWeChatUid | ✔️ | 已测试 | +| 获取登录微信信息 | /loginWeChatInfo | ✔️ | 已测试 | +| 获取消息类型列表 | /list/msgType | ✔️ | 已测试 | +| 获取联系人列表 | /list/contacts | ✔️ | 已测试 | +| 获取数据库表名称列表 | /list/dbTableName | ✔️ | 已测试 | +| 获取指定数据库中的表列表 | /list/dbTable | ✔️ | 已测试 | +| 执行数据库查询SQL | /exec/dbQuerySql | ✔️ | 已测试 | +| 发送消息汇总入口 | /send/msgMaster | ❌ | 预留 | +| 发送文本消息 | /send/textMsg | ✔️ | 已测试 | +| 发送富文本消息 | /send/richTextMsg | ❌ | 缩略图参数需要为空,否则会发送失败 | +| 发送XML消息 | /send/xmlMsg | ❌ | 该版本不支持 | +| 发送图片消息 | /send/imageMsg | ✔️ | 已测试 | +| 发送表情消息 | /send/emojiMsg | ❌ | 该版本不支持 | +| 发送文件消息 | /send/fileMsg | ❌ | 该版本不支持 | +| 拍一拍群友 | /patOnePat | ✔️ | 已测试 | +| 撤回消息 | /revokeMsg | ❌ | 该版本不支持 | +| 通过好友申请 | /passFriendApply | ❌ | 该版本不支持 | +| 添加群成员为微信好友 | /addFriend/groupMember | ❔ | 待测试 | +| 查询群成员 | /groupMember/list | ✔️ | 已测试 | +| 邀请群成员 | /groupMember/invite | ❔ | 待测试 | +| 删除群成员 | /groupMember/delete | ❔ | 待测试 | +| 查询朋友圈 | /friendCircle | ❔ | 待测试 | +| 接收转账 | /receiveTransfer | ❌ | 该版本不支持 | ### 已知BUG - 1.发送表情微信客户端闪退 - `待修复` - 2.发送富文本包含thumbnailUrl参数会导致消息发送不出去 - `待修复` +- 3.发送文件成功之后客户端崩溃 - `待修复` + +### 2025-01-04 + +#### ⛰️ Features + +- 退群监测功能关闭,待完善,目前未开启 +- 说明文档更新 + +#### 🐛 Bug fixes +- 微信端退出之后,调用接口返回客户端状态异常提示 + +### 2024-12-27 + +#### ⛰️ Features + +- 查询群成员返回类新增字段 +- 新增退群监测功能 +- 说明文档更新 + +### 2024-12-25 + +#### ⛰️ Features + +- 新增通过好友申请接口 +- 新增添加群成员为微信好友接口 +- 新增邀请群成员接口 +- 新增删除群成员接口 +- 新增刷新朋友圈接口 +- 新增撤回消息接口 +- 接收转账 +- 查询群成员请求地址变更 +- 消息回调配置文件参数名称修改 +- 封装接收到消息之后的业务操作类 ### 2024-12-24 @@ -44,4 +94,54 @@ - 适配SDK39.3.3版本 - wcf.proto文件部分字段类型修改 -- 消息转发适配多种消息类型 \ No newline at end of file +- 消息转发适配多种消息类型 + +
+ +___ + +

+ +## v39.2.4 - 推荐✨ + +### 版本列表 + +下载地址:[v39.2.4](https://github.com/lich0821/WeChatFerry/releases/tag/v39.2.4) + +| 名称 | 版本 | 文件名 | +|-----------------|-----------|---------------------------| +| 微信客户端 | 3.9.10.27 | WeChatSetup-3.9.10.27.exe | +| WeChatFerry-SDK | 39.2.4 | v39.2.4.zip | + +### 功能列表 + +| 接口名 | 地址 | 是否支持 | 备注 | +|----------------|------------------------|------|--------| +| 查询登录状态 | /loginStatus | ✔️ | 已测试 | +| 获取登录微信内部识别号UID | /loginWeChatUid | ✔️ | 已测试 | +| 获取登录微信信息 | /loginWeChatInfo | ✔️ | 已测试 | +| 获取消息类型列表 | /list/msgType | ✔️ | 已测试 | +| 获取联系人列表 | /list/contacts | ✔️ | 已测试 | +| 获取数据库表名称列表 | /list/dbTableName | ✔️ | 已测试 | +| 获取指定数据库中的表列表 | /list/dbTable | ✔️ | 已测试 | +| 执行数据库查询SQL | /exec/dbQuerySql | ✔️ | 已测试 | +| 发送消息汇总入口 | /send/msgMaster | ❌ | 预留 | +| 发送文本消息 | /send/textMsg | ✔️ | 已测试 | +| 发送富文本消息 | /send/richTextMsg | ✔️ | 已测试 | +| 发送XML消息 | /send/xmlMsg | ❌ | 该版本不支持 | +| 发送图片消息 | /send/imageMsg | ✔️ | 已测试 | +| 发送表情消息 | /send/emojiMsg | ✔️ | 已测试 | +| 发送文件消息 | /send/fileMsg | ✔️ | 已测试 | +| 拍一拍群友 | /patOnePat | ✔️ | 已测试 | +| 撤回消息 | /revokeMsg | ❌ | 该版本不支持 | +| 通过好友申请 | /passFriendApply | ❌ | 该版本不支持 | +| 添加群成员为微信好友 | /addFriend/groupMember | ❔ | 待测试 | +| 查询群成员 | /groupMember/list | ✔️ | 已测试 | +| 邀请群成员 | /groupMember/invite | ❔ | 待测试 | +| 删除群成员 | /groupMember/delete | ❔ | 待测试 | +| 查询朋友圈 | /friendCircle | ❔ | 待测试 | +| 接收转账 | /receiveTransfer | ❌ | 该版本不支持 | + +
+ +___ \ No newline at end of file diff --git a/clients/java/wechat-ferry-mvn/README.MD b/clients/java/wechat-ferry-mvn/README.MD index 9fd296b..9822992 100644 --- a/clients/java/wechat-ferry-mvn/README.MD +++ b/clients/java/wechat-ferry-mvn/README.MD @@ -13,7 +13,7 @@ |-----------------|-----------|----| | JDK | 1.8+ | √ | | Maven | 3.8+ | √ | -| 微信 | 3.9.11.25 | √ | +| 微信客户端 | 3.9.11.25 | √ | | WeChatFerry-SDK | 39.3.3 | √ | | MySQL | 8.0+ | 备用 | @@ -35,6 +35,15 @@ 把刚下载的最新发布文件解压到本项目中的 dll 文件目录下,直接替换原因文件即可 +替换 `clients/java/wechat-ferry-mvn/dll` 目录下(也可以在配置文件中改为自定义的目录) + +- sdk.dll +- spy.dll +- spy_debug.dll + +> 如果之前已经使用本项目启动过微信,此时替换发现替换不了,是因为正则运行的微信客户端正在使用该文件, +> 请退出并关闭微信客户端之后再进行替换 + ### 修改配置文件 配置文件:src/main/resources/application.yml @@ -71,15 +80,17 @@ swagger地址:http://localhost:9201/swagger-ui/index.html ### 核心依赖 -| 依赖 | 版本 | 说明 | -|---------------|--------|----------| -| Spring Boot | 2.7.18 | 基础框架 | -| protobuf-java | 3.22.2 | rpc | -| jna | 5.6.0 | 态访问系统本地库 | -| nng-java | 1.4.0 | 本地包 | -| fastjson2 | 2.0.52 | 序列化 | -| dom4j | 2.1.3 | XML解析包 | -| httpclient | 4.5.13 | 客户端请求 | +| 依赖 | 版本 | 说明 | +|---------------|-------------|----------| +| Spring Boot | 2.7.18 | 基础框架 | +| protobuf-java | 3.22.2 | rpc | +| jna | 5.6.0 | 态访问系统本地库 | +| nng-java | 1.4.0 | 本地包 | +| fastjson2 | 2.0.52 | 序列化 | +| dom4j | 2.1.3 | XML解析包 | +| httpclient | 4.5.13 | 客户端请求 | +| validation | 2.0.1.Final | 参数校验 | +| springfox | 3.0.0 | swagger3 | ### 模块结构 @@ -93,16 +104,22 @@ wechat-ferry-mvn │ ├─main 重启命令 │ │ ├─java(com.wechat.ferry) java代码目录 │ │ │ ├─config 配置 +│ │ │ ├─constant 常量 +│ │ │ ├─controller 控制层(API接口) │ │ │ ├─entity 聚合模型 │ │ │ │ ├─dto DTO模型 │ │ │ │ ├─po 数据库实体(与表结构一一对应,否则请使用DTO) │ │ │ │ ├─proto PB实体 │ │ │ │ └─vo 视图层返回体目录 │ │ │ ├─enums 枚举 +│ │ │ ├─exception 异常封装 │ │ │ ├─handle 处理层 -│ │ │ ├─service 业务接口 +│ │ │ ├─service 业务层 │ │ │ │ └─impl 业务实现类 -│ │ │ ├─utils 工具类 +│ │ │ ├─strategy 策略层 +│ │ │ │ └─impl 策略实现类(如接收到消息之后的事件处理可以放在这里) +│ │ │ ├─task 定时任务 +│ │ │ ├─utils 工具层 │ │ │ └─WcferryApplication.java 启动类 │ │ │ │ │ │resources 资源目录 diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/aggregation/.gitkeep b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/aggregation/.gitkeep new file mode 100644 index 0000000..a10d4fe --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/aggregation/.gitkeep @@ -0,0 +1,3 @@ +# Ignore everything in this directory +* +# Except this file !.gitkeep \ No newline at end of file diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/aggregation/facade/ChatRoomDo.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/aggregation/facade/ChatRoomDo.java new file mode 100644 index 0000000..586b4a5 --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/aggregation/facade/ChatRoomDo.java @@ -0,0 +1,15 @@ +package com.wechat.ferry.aggregation.facade; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +/** + * 聚合模型类-联系人 + * + * @author chandler + * @date 2023-06-08 22:39:53 + */ +@Slf4j +@Data +public class ChatRoomDo { +} diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/aggregation/facade/ContactDo.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/aggregation/facade/ContactDo.java new file mode 100644 index 0000000..bfb43d2 --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/aggregation/facade/ContactDo.java @@ -0,0 +1,190 @@ +package com.wechat.ferry.aggregation.facade; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import com.wechat.ferry.config.WeChatFerryProperties; +import com.wechat.ferry.entity.po.wcf.Contact; +import com.wechat.ferry.entity.proto.Wcf; +import com.wechat.ferry.enums.DatabaseNameEnum; +import com.wechat.ferry.enums.WxContactsMixedEnum; +import com.wechat.ferry.enums.WxContactsOfficialEnum; +import com.wechat.ferry.enums.WxContactsTypeEnum; +import com.wechat.ferry.handle.WeChatSocketClient; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +/** + * 聚合模型类-联系人 + * + * @author chandler + * @date 2023-06-08 22:39:53 + */ +@Slf4j +@Data +public class ContactDo extends Contact { + + /** + * 微信内部识别号UID + */ + @ApiModelProperty(value = "微信内部识别号UID") + private String weChatUid; + + /** + * 联系人类型 + */ + @ApiModelProperty(value = "联系人类型") + private String contactType; + + /** + * 展示名称 + * 有备注优先展示备注 + */ + @ApiModelProperty(value = "展示名称") + private String showName; + + /** + * 根据自定义SQL查询联系人列表 + * + * @param wechatSocketClient 通信客户端 + * @param weChatFerryProperties 配置文件 + * + * @author chandler + * @date 2024-12-27 16:06 + */ + public List queryContactListBySql(WeChatSocketClient wechatSocketClient, WeChatFerryProperties weChatFerryProperties) { + List list = new ArrayList<>(); + // 查询联系人 + List dbContactList = wechatSocketClient.querySql(DatabaseNameEnum.MICRO_MSG.getCode(), + "SELECT UserName, Alias, DelFlag, Type, VerifyFlag, Remark, NickName, LabelIDList, DomainList, ChatRoomType, PYInitial, QuanPin, RemarkPYInitial, RemarkQuanPin, ChatRoomNotify FROM Contact;"); + if (!CollectionUtils.isEmpty(dbContactList)) { + for (Wcf.DbRow dbRow : dbContactList) { + List dbFieldList = dbRow.getFieldsList(); + if (!ObjectUtils.isEmpty(dbFieldList)) { + ContactDo po = new ContactDo(); + for (Wcf.DbField dbField : dbFieldList) { + String content = (String)wechatSocketClient.convertSqlVal(dbField.getType(), dbField.getContent()); + // 用户名 + if ("UserName".equals(dbField.getColumn())) { + po.setUserName(content); + po.setWeChatUid(content); + // 设置类型 + String type = convertContactType(content, weChatFerryProperties); + po.setContactType(type); + } + // 用户名 + if ("Alias".equals(dbField.getColumn())) { + po.setAlias(content); + } + // 昵称 + if ("NickName".equals(dbField.getColumn())) { + po.setNickname(content); + } + // 删除标志 + if ("DelFlag".equals(dbField.getColumn())) { + po.setDelFlag(Integer.valueOf(content)); + } + // + if ("VerifyFlag".equals(dbField.getColumn())) { + po.setVerifyFlag(Integer.valueOf(content)); + } + // + if ("Remark".equals(dbField.getColumn())) { + po.setRemark(content); + } + // + if ("LabelIDList".equals(dbField.getColumn())) { + po.setLabelIdList(content); + } + // + if ("DomainList".equals(dbField.getColumn())) { + po.setDomainList(content); + } + // + if ("ChatRoomType".equals(dbField.getColumn())) { + po.setChatRoomType(Integer.valueOf(content)); + } + } + list.add(po); + } + } + } + return list; + } + + /** + * 转换联系人类型 + * 类型判断,存在优先级的,官方杂号优先级高于微信公众号(如果定义重复了,常规禁止重复,手机端和电脑端分类不同) + * + * @param weChatUid 微信识别号 + * @param weChatFerryProperties 配置文件 + * + * @author chandler + * @date 2024-12-27 15:56 + */ + public static String convertContactType(String weChatUid, WeChatFerryProperties weChatFerryProperties) { + String type = ""; + // 官方杂号集合 + Map mixedNoMap = WxContactsMixedEnum.toCodeNameMap(); + mixedNoMap.putAll(convertContactsTypeProperties(weChatFerryProperties.getContactsTypeMixed())); + // 公众号 + Map officialMap = WxContactsOfficialEnum.toCodeNameMap(); + officialMap.putAll(convertContactsTypeProperties(weChatFerryProperties.getContactsTypeOfficial())); + + // 类型判断,存在优先级的,官方杂号优先级高于微信公众号(如果定义重复了,常规禁止重复,手机端和电脑端分类不同) + if (weChatUid.endsWith(WxContactsTypeEnum.WORK.getAffix())) { + // 企微 + type = WxContactsTypeEnum.WORK.getCode(); + } else if (weChatUid.endsWith(WxContactsTypeEnum.GROUP.getAffix()) || weChatUid.endsWith("@im.chatroom")) { + // 群聊 @im.chatroom 这种是很早之前的格式,单独例举 + type = WxContactsTypeEnum.GROUP.getCode(); + } else if (mixedNoMap.containsKey(weChatUid)) { + // 官方杂号 + type = WxContactsTypeEnum.OFFICIAL_MIXED_NO.getCode(); + } else if (weChatUid.startsWith(WxContactsTypeEnum.OFFICIAL_ACCOUNT.getAffix())) { + // 微信公众号 + type = WxContactsTypeEnum.OFFICIAL_ACCOUNT.getCode(); + } else if (officialMap.containsKey(weChatUid)) { + type = WxContactsTypeEnum.OFFICIAL_ACCOUNT.getCode(); + } else { + // 个微 + type = WxContactsTypeEnum.PERSON.getCode(); + } + return type; + } + + /** + * 转换联系人类型配置 + * + * @param list 配置参数 + * @return map key:code val:name + * + * @author chandler + * @date 2024-12-24 16:55 + */ + public static Map convertContactsTypeProperties(List list) { + Map map = new HashMap<>(); + if (!CollectionUtils.isEmpty(list)) { + for (String str : list) { + String key = str; + String val = str; + // 存在名称则分割 + if (str.contains("|")) { + int index = str.indexOf("|"); + key = str.substring(0, index); + val = str.substring(index + 1); + } + map.put(key, val); + } + } + return map; + } + +} diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/config/WeChatConfiguration.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/config/WeChatConfiguration.java index 2e9b673..7564627 100644 --- a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/config/WeChatConfiguration.java +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/config/WeChatConfiguration.java @@ -81,7 +81,7 @@ public class WeChatConfiguration { // 只打印 // wechatSocketClient.printWxMsg(wechatSocketClient.getMsg()); // 转发到boot项目进行消息处理 - wechatSocketClient.forwardMsg(wechatSocketClient.getMsg(), url); + wechatSocketClient.localCallbackAnalyzeMsg(wechatSocketClient.getMsg(), url); } } }); diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/config/WeChatFerryProperties.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/config/WeChatFerryProperties.java index 46893a9..28e5789 100644 --- a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/config/WeChatFerryProperties.java +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/config/WeChatFerryProperties.java @@ -47,24 +47,24 @@ public class WeChatFerryProperties { private List openMsgGroups; /** - * 接收消息转发开关 + * 接收消息回调开关 */ - private Boolean receiveMsgFwdSwitch = false; + private Boolean receiveMsgCallbackSwitch = false; /** - * 接收消息转发URL + * 接收消息回调地址 */ - private List receiveMsgFwdUrls; + private List receiveMsgCallbackUrls; /** - * 发送消息转发标识 1-关闭 2-全转发 3-发送成功才转发 + * 发送消息回调标识 1-关闭 2-全部回调 3-发送成功才回调 */ - private String sendMsgFwdFlag = "1"; + private String sendMsgCallbackFlag = "1"; /** - * 发送消息转发URL + * 发送消息回调地址 */ - private List sendMsgFwdUrls; + private List sendMsgCallbackUrls; /** * 调用第三方服务客户端成功状态码 diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/controller/WeChatDllController.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/controller/WeChatDllController.java index e52f160..48b780c 100644 --- a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/controller/WeChatDllController.java +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/controller/WeChatDllController.java @@ -10,10 +10,16 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.wechat.ferry.entity.TResponse; +import com.wechat.ferry.entity.vo.request.WxPpWcfAddFriendGroupMemberReq; import com.wechat.ferry.entity.vo.request.WxPpWcfDatabaseSqlReq; import com.wechat.ferry.entity.vo.request.WxPpWcfDatabaseTableReq; +import com.wechat.ferry.entity.vo.request.WxPpWcfDeleteGroupMemberReq; import com.wechat.ferry.entity.vo.request.WxPpWcfGroupMemberReq; +import com.wechat.ferry.entity.vo.request.WxPpWcfInviteGroupMemberReq; +import com.wechat.ferry.entity.vo.request.WxPpWcfPassFriendApplyReq; import com.wechat.ferry.entity.vo.request.WxPpWcfPatOnePatMsgReq; +import com.wechat.ferry.entity.vo.request.WxPpWcfReceiveTransferReq; +import com.wechat.ferry.entity.vo.request.WxPpWcfRevokeMsgReq; import com.wechat.ferry.entity.vo.request.WxPpWcfSendEmojiMsgReq; import com.wechat.ferry.entity.vo.request.WxPpWcfSendFileMsgReq; import com.wechat.ferry.entity.vo.request.WxPpWcfSendImageMsgReq; @@ -115,13 +121,6 @@ public class WeChatDllController { return TResponse.ok(ResponseCodeEnum.SUCCESS, list); } - @ApiOperation(value = "查询群成员", notes = "queryGroupMember") - @PostMapping(value = "/list/groupMember") - public TResponse> queryGroupMember(@Validated @RequestBody WxPpWcfGroupMemberReq request) { - List list = weChatDllService.queryGroupMember(request); - return TResponse.ok(ResponseCodeEnum.SUCCESS, list); - } - @ApiOperation(value = "发送消息汇总入口", notes = "sendMsgMaster") @PostMapping(value = "/send/msgMaster") public TResponse sendMsgMaster(@Validated @RequestBody String jsonString) { @@ -184,12 +183,12 @@ public class WeChatDllController { // return TResponse.ok(ResponseCodeEnum.SUCCESS, list); // } - // @ApiOperation(value = "撤回消息", notes = "queryMsgTypeList") - // @PostMapping(value = "/list/msgType") - // public TResponse queryMsgTypeList() { - // return TResponse.ok(ResponseCodeEnum.SUCCESS, list); - // } - // + @ApiOperation(value = "撤回消息", notes = "revokeMsg") + @PostMapping(value = "/revokeMsg") + public TResponse revokeMsg(@Validated @RequestBody WxPpWcfRevokeMsgReq request) { + return TResponse.ok(ResponseCodeEnum.SUCCESS); + } + // @ApiOperation(value = "转发消息", notes = "queryMsgTypeList") // @PostMapping(value = "/list/msgType") // public TResponse queryMsgTypeList() { @@ -209,19 +208,55 @@ public class WeChatDllController { // } // - // @ApiOperation(value = "通过好友申请", notes = "queryMsgTypeList") - // @PostMapping(value = "/list/msgType") - // public TResponse friendApply(@Validated @RequestBody WxPpPatOnePatMsgReq request) { - // // WxPpSendPatOnePatMsgResp resp = weChatDllService.patOnePat(request); - // return TResponse.ok(ResponseCodeEnum.SUCCESS, resp); - // } + @ApiOperation(value = "通过好友申请", notes = "passFriendApply") + @PostMapping(value = "/passFriendApply") + public TResponse passFriendApply(@Validated @RequestBody WxPpWcfPassFriendApplyReq request) { + weChatDllService.passFriendApply(request); + return TResponse.ok(ResponseCodeEnum.SUCCESS); + } + + @ApiOperation(value = "添加群成员为微信好友", notes = "addFriendGroupMember") + @PostMapping(value = "/addFriend/groupMember") + public TResponse addFriendGroupMember(@Validated @RequestBody WxPpWcfAddFriendGroupMemberReq request) { + weChatDllService.addFriendGroupMember(request); + return TResponse.ok(ResponseCodeEnum.SUCCESS); + } + + @ApiOperation(value = "查询群成员列表", notes = "queryGroupMemberList") + @PostMapping(value = "/groupMember/list") + public TResponse> queryGroupMemberList(@Validated @RequestBody WxPpWcfGroupMemberReq request) { + List list = weChatDllService.queryGroupMemberList(request); + return TResponse.ok(ResponseCodeEnum.SUCCESS, list); + } + + @ApiOperation(value = "邀请群成员", notes = "inviteGroupMember") + @PostMapping(value = "/groupMember/invite") + public TResponse inviteGroupMember(@Validated @RequestBody WxPpWcfInviteGroupMemberReq request) { + weChatDllService.inviteGroupMember(request); + return TResponse.ok(ResponseCodeEnum.SUCCESS); + } + + @ApiOperation(value = "删除群成员", notes = "deleteGroupMember") + @PostMapping(value = "/groupMember/delete") + public TResponse deleteGroupMember(@Validated @RequestBody WxPpWcfDeleteGroupMemberReq request) { + weChatDllService.deleteGroupMember(request); + return TResponse.ok(ResponseCodeEnum.SUCCESS); + } + + @ApiOperation(value = "查询朋友圈", notes = "queryFriendCircle") + @PostMapping(value = "/friendCircle") + public TResponse queryFriendCircle() { + weChatDllService.queryFriendCircle(); + return TResponse.ok(ResponseCodeEnum.SUCCESS); + } + + @ApiOperation(value = "接收转账", notes = "receiveTransfer") + @PostMapping(value = "/receiveTransfer") + public TResponse receiveTransfer(@Validated @RequestBody WxPpWcfReceiveTransferReq request) { + weChatDllService.receiveTransfer(request); + return TResponse.ok(ResponseCodeEnum.SUCCESS); + } - // @ApiOperation(value = "获取朋友圈消息", notes = "queryMsgTypeList") - // @PostMapping(value = "/list/msgType") - // public TResponse queryMsgTypeList() { - // return TResponse.ok(ResponseCodeEnum.SUCCESS, list); - // } - // // @ApiOperation(value = "下载图片、视频、文件", notes = "queryMsgTypeList") // @PostMapping(value = "/list/msgType") // public TResponse queryMsgTypeList() { @@ -233,23 +268,5 @@ public class WeChatDllController { // public TResponse queryMsgTypeList() { // return TResponse.ok(ResponseCodeEnum.SUCCESS, list); // } - // - // @ApiOperation(value = "添加群成员", notes = "queryMsgTypeList") - // @PostMapping(value = "/list/msgType") - // public TResponse queryMsgTypeList() { - // return TResponse.ok(ResponseCodeEnum.SUCCESS, list); - // } - // - // @ApiOperation(value = "删除群成员", notes = "queryMsgTypeList") - // @PostMapping(value = "/list/msgType") - // public TResponse queryMsgTypeList() { - // return TResponse.ok(ResponseCodeEnum.SUCCESS, list); - // } - // - // @ApiOperation(value = "邀请群成员", notes = "queryMsgTypeList") - // @PostMapping(value = "/list/msgType") - // public TResponse queryMsgTypeList() { - // return TResponse.ok(ResponseCodeEnum.SUCCESS, list); - // } } diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/dto/WxPpMsgDTO.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/dto/WxPpMsgDTO.java index b30515a..9e341df 100644 --- a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/dto/WxPpMsgDTO.java +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/dto/WxPpMsgDTO.java @@ -7,7 +7,7 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; /** - * DTO-ge微信消息 + * DTO-个微信消息 * * @author chandler * @date 2024-09-26 19:56 diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/po/wcf/ChatRoom.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/po/wcf/ChatRoom.java new file mode 100644 index 0000000..3f685c2 --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/po/wcf/ChatRoom.java @@ -0,0 +1,35 @@ +package com.wechat.ferry.entity.po.wcf; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 实体类-群信息表 + * + * @author chandler + * @date 2024-12-27 10:01 + */ +@Data +@ApiModel(value = "ChatRoom", description = "群信息表") +public class ChatRoom { + + /** + * 群名称 + */ + @ApiModelProperty(value = "群名称") + private String chatRoomName; + + /** + * 用户名称列表 + */ + @ApiModelProperty(value = "用户名称列表") + private String userNameList; + + /** + * 显示名称列表 + */ + @ApiModelProperty(value = "显示名称列表") + private String displayNameList; + +} diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/po/wcf/ChatRoomInfo.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/po/wcf/ChatRoomInfo.java new file mode 100644 index 0000000..fa078e6 --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/po/wcf/ChatRoomInfo.java @@ -0,0 +1,47 @@ +package com.wechat.ferry.entity.po.wcf; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 实体类-群详细信息表 + * + * @author chandler + * @date 2024-12-27 10:03 + */ +@Data +@ApiModel(value = "ChatRoomInfo", description = "群详细信息表") +public class ChatRoomInfo { + + /** + * 群名称 + */ + @ApiModelProperty(value = "群名称") + private String chatRoomName; + + /** + * 群公告 + */ + @ApiModelProperty(value = "群公告") + private String announcement; + + /** + * 公告编辑者 + */ + @ApiModelProperty(value = "公告编辑者") + private String announcementEditor; + + /** + * 公告发布时间 + */ + @ApiModelProperty(value = "公告发布时间") + private String announcementPublishTime; + + /** + * 群状态 + */ + @ApiModelProperty(value = "群状态") + private Integer chatRoomStatus; + +} diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/po/wcf/Contact.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/po/wcf/Contact.java new file mode 100644 index 0000000..bc1f1ef --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/po/wcf/Contact.java @@ -0,0 +1,71 @@ +package com.wechat.ferry.entity.po.wcf; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 实体类-联系人表 + * + * @author chandler + * @date 2024-12-27 09:47 + */ +@Data +@ApiModel(value = "Contact对象", description = "联系人表") +public class Contact { + + /** + * 用户名 + */ + @ApiModelProperty(value = "用户名") + private String userName; + + /** + * 别名 + */ + @ApiModelProperty(value = "别名") + private String alias; + + /** + * 昵称 + */ + @ApiModelProperty(value = "昵称") + private String nickname; + + /** + * 删除标志 + */ + @ApiModelProperty(value = "删除标志") + private Integer delFlag; + + /** + * 验证标志 + */ + @ApiModelProperty(value = "验证标志") + private Integer verifyFlag; + + /** + * 备注 + */ + @ApiModelProperty(value = "备注") + private String remark; + + /** + * 标签ID列表 + */ + @ApiModelProperty(value = "标签ID列表") + private String labelIdList; + + /** + * 域名列表 + */ + @ApiModelProperty(value = "域名列表") + private String domainList; + + /** + * 群类型 + */ + @ApiModelProperty(value = "群类型") + private Integer chatRoomType; + +} diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/po/wcf/ContactHeadImgUrl.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/po/wcf/ContactHeadImgUrl.java new file mode 100644 index 0000000..2379c96 --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/po/wcf/ContactHeadImgUrl.java @@ -0,0 +1,35 @@ +package com.wechat.ferry.entity.po.wcf; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 实体类-联系人头像信息表 + * + * @author chandler + * @date 2024-12-27 09:59 + */ +@Data +@ApiModel(value = "ContactHeadImgUrl对象", description = "联系人头像信息表") +public class ContactHeadImgUrl { + + /** + * 用户名 + */ + @ApiModelProperty(value = "用户名") + private String userName; + + /** + * 小头像URL + */ + @ApiModelProperty(value = "小头像URL") + private String smallHeadIngUrl; + + /** + * 大头像URL + */ + @ApiModelProperty(value = "大头像URL") + private String bigHeadIngUrl; + +} diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/po/wcf/RevokeMsgStorage.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/po/wcf/RevokeMsgStorage.java new file mode 100644 index 0000000..b7889a5 --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/po/wcf/RevokeMsgStorage.java @@ -0,0 +1,35 @@ +package com.wechat.ferry.entity.po.wcf; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 实体类-撤回消息存储表 + * + * @author chandler + * @date 2024-12-27 10:08 + */ +@Data +@ApiModel(value = "RevokeMsgStorage对象", description = "撤回消息存储表") +public class RevokeMsgStorage { + + /** + * 创建时间 + */ + @ApiModelProperty(value = "创建时间") + private Integer createTime; + + /** + * 消息服务ID + */ + @ApiModelProperty(value = "消息服务ID") + private Integer msgSvrId; + + /** + * 撤回服务ID + */ + @ApiModelProperty(value = "撤回服务ID") + private Integer revokeSvrId; + +} diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/request/WxPpWcfAddFriendGroupMemberReq.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/request/WxPpWcfAddFriendGroupMemberReq.java new file mode 100644 index 0000000..1ab873f --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/request/WxPpWcfAddFriendGroupMemberReq.java @@ -0,0 +1,34 @@ +package com.wechat.ferry.entity.vo.request; + +import javax.validation.constraints.NotBlank; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * 请求入参-添加群成员为好友 + * + * @author chandler + * @date 2024-12-25 09:53 + */ +@Data +@ApiModel(value = "wxPpWcfAddFriendGroupMemberReq", description = "个微WCF添加群成员为好友请求入参") +public class WxPpWcfAddFriendGroupMemberReq { + + /** + * 群编号 + */ + @NotBlank(message = "群编号不能为空") + @ApiModelProperty(value = "群编号") + private String groupNo; + + /** + * 待添加的群成员列表 + */ + @ApiModelProperty(value = "待添加的群成员列表") + private List groupMembers; + +} diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/request/WxPpWcfDeleteGroupMemberReq.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/request/WxPpWcfDeleteGroupMemberReq.java new file mode 100644 index 0000000..4055c09 --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/request/WxPpWcfDeleteGroupMemberReq.java @@ -0,0 +1,34 @@ +package com.wechat.ferry.entity.vo.request; + +import java.util.List; + +import javax.validation.constraints.NotBlank; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 请求入参-个微WCF删除群成员 + * + * @author chandler + * @date 2024-12-25 10:01 + */ +@Data +@ApiModel(value = "wxPpWcfDeleteGroupMemberReq", description = "个微WCF删除群成员请求入参") +public class WxPpWcfDeleteGroupMemberReq { + + /** + * 群编号 + */ + @NotBlank(message = "群编号不能为空") + @ApiModelProperty(value = "群编号") + private String groupNo; + + /** + * 待删除的群成员列表 + */ + @ApiModelProperty(value = "待删除的群成员列表") + private List groupMembers; + +} diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/request/WxPpWcfInviteGroupMemberReq.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/request/WxPpWcfInviteGroupMemberReq.java new file mode 100644 index 0000000..97bd6cc --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/request/WxPpWcfInviteGroupMemberReq.java @@ -0,0 +1,34 @@ +package com.wechat.ferry.entity.vo.request; + +import java.util.List; + +import javax.validation.constraints.NotBlank; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 请求入参-个微WCF邀请群成员 + * + * @author chandler + * @date 2024-12-25 09:51 + */ +@Data +@ApiModel(value = "wxPpWcfInviteGroupMemberReq", description = "个微WCF邀请群成员请求入参") +public class WxPpWcfInviteGroupMemberReq { + + /** + * 群编号 + */ + @NotBlank(message = "群编号不能为空") + @ApiModelProperty(value = "群编号") + private String groupNo; + + /** + * 待邀请的群成员列表 + */ + @ApiModelProperty(value = "待邀请的群成员列表") + private List groupMembers; + +} diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/request/WxPpWcfPassFriendApplyReq.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/request/WxPpWcfPassFriendApplyReq.java new file mode 100644 index 0000000..1c801c5 --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/request/WxPpWcfPassFriendApplyReq.java @@ -0,0 +1,45 @@ +package com.wechat.ferry.entity.vo.request; + +import javax.validation.constraints.NotBlank; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 请求入参-通过好友申请 + * + * @author chandler + * @date 2024-12-25 09:30 + */ +@Data +@ApiModel(value = "wxPpWcfPassFriendApplyReq", description = "个微WCF通过好友申请请求入参") +public class WxPpWcfPassFriendApplyReq { + + /** + * 申请人 + * v3 xml.attrib["encryptusername"] + * 加密用户名 (好友申请消息里 v3 开头的字符串) + */ + @NotBlank(message = "申请人不能为空") + @ApiModelProperty(value = "申请人") + private String applicant; + + /** + * 审核人 + * v4 xml.attrib["ticket"] + * Ticket (好友申请消息里 v4 开头的字符串) + * 一般指自己,别人申请添加,自己审核是否通过 + */ + @NotBlank(message = "审核人不能为空") + @ApiModelProperty(value = "审核人") + private String reviewer; + + /** + * 场景 + * 申请方式 (好友申请消息里的 scene); 为了兼容旧接口,默认为扫码添加 (30) + */ + @ApiModelProperty(value = "场景") + private String scene; + +} diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/request/WxPpWcfReceiveTransferReq.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/request/WxPpWcfReceiveTransferReq.java new file mode 100644 index 0000000..b7e3bea --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/request/WxPpWcfReceiveTransferReq.java @@ -0,0 +1,35 @@ +package com.wechat.ferry.entity.vo.request; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 请求入参-个微WCF接收转账 + * + * @author chandler + * @date 2024-12-25 13:46 + */ +@Data +@ApiModel(value = "wxPpWcfReceiveTransferReq", description = "个微WCF接收转账请求入参") +public class WxPpWcfReceiveTransferReq { + + /** + * 转账人 + */ + @ApiModelProperty(value = "转账人") + private String weChatUid; + + /** + * 转账编号 transferId + */ + @ApiModelProperty(value = "转账编号") + private String transferId; + + /** + * 交易编号 Transaction id + */ + @ApiModelProperty(value = "交易编号") + private String transactionId; + +} diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/request/WxPpWcfRevokeMsgReq.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/request/WxPpWcfRevokeMsgReq.java new file mode 100644 index 0000000..81abd17 --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/request/WxPpWcfRevokeMsgReq.java @@ -0,0 +1,25 @@ +package com.wechat.ferry.entity.vo.request; + +import javax.validation.constraints.NotBlank; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 请求入参-撤回消息 + * + * @author chandler + * @date 2024-12-25 12:00 + */ +@Data +@ApiModel(value = "wxPpWcfRevokeMsgReq", description = "个微WCF撤回消息请求入参") +public class WxPpWcfRevokeMsgReq { + + /** + * 消息编号 + */ + @ApiModelProperty(value = "场景") + private String msgId; + +} diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/response/WxPpWcfGroupMemberResp.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/response/WxPpWcfGroupMemberResp.java index 326e46d..cfa27a6 100644 --- a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/response/WxPpWcfGroupMemberResp.java +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/vo/response/WxPpWcfGroupMemberResp.java @@ -33,4 +33,16 @@ public class WxPpWcfGroupMemberResp { @ApiModelProperty(value = "状态") private String state; + /** + * 是否自己 + */ + @ApiModelProperty(value = "是否自己") + private Boolean whetherSelf; + + /** + * 是否企微 + */ + @ApiModelProperty(value = "是否企微") + private Boolean whetherWork; + } diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/enums/MsgFwdTypeEnum.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/enums/MsgCallbackTypeEnum.java similarity index 58% rename from clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/enums/MsgFwdTypeEnum.java rename to clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/enums/MsgCallbackTypeEnum.java index c9a7648..787eeb9 100644 --- a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/enums/MsgFwdTypeEnum.java +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/enums/MsgCallbackTypeEnum.java @@ -8,15 +8,15 @@ import lombok.AllArgsConstructor; import lombok.Getter; /** - * 枚举-消息转发开关 - * 1-关闭 2-全转发 3-发送成功才转发 + * 枚举-消息回调开关 + * 1-关闭 2-全部回调 3-发送成功才回调 * * @author chandler * @date 2024/10/01 15:42 */ @Getter @AllArgsConstructor -public enum MsgFwdTypeEnum { +public enum MsgCallbackTypeEnum { /** * 1-关闭 @@ -24,14 +24,14 @@ public enum MsgFwdTypeEnum { CLOSE("1", "关闭"), /** - * 2-全转发 + * 2-全部回调 */ - ALL("2", "全转发"), + ALL("2", "全部回调"), /** - * 3-发送成功才转发 + * 3-发送成功才回调 */ - SUCCESS("3", "发送成功才转发"), + SUCCESS("3", "发送成功才回调"), /** * 未匹配上 @@ -47,12 +47,13 @@ public enum MsgFwdTypeEnum { /** * map集合 key:code val:枚举 */ - public static final Map codeMap = Arrays.stream(values()).collect(Collectors.toMap(MsgFwdTypeEnum::getCode, v -> v)); + public static final Map codeMap = + Arrays.stream(values()).collect(Collectors.toMap(MsgCallbackTypeEnum::getCode, v -> v)); /** * 根据code获取枚举 */ - public static MsgFwdTypeEnum getCodeMap(String code) { + public static MsgCallbackTypeEnum getCodeMap(String code) { return codeMap.getOrDefault(code, UN_MATCH); } diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/enums/MsgEventTypeEnum.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/enums/MsgEventTypeEnum.java new file mode 100644 index 0000000..ae137c1 --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/enums/MsgEventTypeEnum.java @@ -0,0 +1,48 @@ +package com.wechat.ferry.enums; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 枚举-消息事件类型 + * + * @author chandler + * @date 2024/12/27 18:09 + */ +@Getter +@AllArgsConstructor +public enum MsgEventTypeEnum { + + /** + * 1-注入成功 + */ + INJECT("1", "注入成功"), + + /** + * 未匹配上 + */ + UN_MATCH("", null), + + // 结束 + ; + + private final String code; + private final String name; + + /** + * map集合 key:code val:枚举 + */ + public static final Map codeMap = Arrays.stream(values()).collect(Collectors.toMap(MsgEventTypeEnum::getCode, v -> v)); + + /** + * 根据code获取枚举 + */ + public static MsgEventTypeEnum getCodeMap(String code) { + return codeMap.getOrDefault(code, UN_MATCH); + } + +} diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/enums/ReceiveMsgChannelEnum.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/enums/ReceiveMsgChannelEnum.java new file mode 100644 index 0000000..f279c85 --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/enums/ReceiveMsgChannelEnum.java @@ -0,0 +1,49 @@ +package com.wechat.ferry.enums; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 枚举-接收消息处理渠道 + * + * @author chandler + * @date 2024/12/25 14:15 + */ +@Getter +@AllArgsConstructor +public enum ReceiveMsgChannelEnum { + + /** + * 1-签到 + */ + SIGN_IN("1", "签到"), + + /** + * 未匹配上 + */ + UN_MATCH("", null), + + // 结束 + ; + + private final String code; + private final String name; + + /** + * map集合 key:code val:枚举 + */ + public static final Map codeMap = + Arrays.stream(values()).collect(Collectors.toMap(ReceiveMsgChannelEnum::getCode, v -> v)); + + /** + * 根据code获取枚举 + */ + public static ReceiveMsgChannelEnum getCodeMap(String code) { + return codeMap.getOrDefault(code, UN_MATCH); + } + +} diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/handle/WeChatSocketClient.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/handle/WeChatSocketClient.java index 7f34ad4..55829c1 100644 --- a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/handle/WeChatSocketClient.java +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/handle/WeChatSocketClient.java @@ -1,25 +1,29 @@ package com.wechat.ferry.handle; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; +import java.util.function.Function; import org.springframework.util.ObjectUtils; import com.alibaba.fastjson2.JSONObject; +import com.google.protobuf.ByteString; import com.sun.jna.Native; import com.wechat.ferry.entity.dto.WxPpMsgDTO; import com.wechat.ferry.entity.proto.Wcf.DbQuery; import com.wechat.ferry.entity.proto.Wcf.DbRow; import com.wechat.ferry.entity.proto.Wcf.DecPath; import com.wechat.ferry.entity.proto.Wcf.Functions; -import com.wechat.ferry.entity.proto.Wcf.MemberMgmt; import com.wechat.ferry.entity.proto.Wcf.Request; import com.wechat.ferry.entity.proto.Wcf.Response; -import com.wechat.ferry.entity.proto.Wcf.Verification; import com.wechat.ferry.entity.proto.Wcf.WxMsg; +import com.wechat.ferry.exception.BizException; import com.wechat.ferry.service.SDK; import com.wechat.ferry.utils.HttpClientUtil; import com.wechat.ferry.utils.XmlJsonConvertUtil; @@ -117,14 +121,21 @@ public class WeChatSocketClient { public Response sendCmd(Request req) { try { + // 设置超时时间 20s + cmdSocket.setSendTimeout(20000); ByteBuffer bb = ByteBuffer.wrap(req.toByteArray()); cmdSocket.send(bb); ByteBuffer ret = ByteBuffer.allocate(BUFFER_SIZE); long size = cmdSocket.receive(ret, true); return Response.parseFrom(Arrays.copyOfRange(ret.array(), 0, (int)size)); } catch (Exception e) { - log.error("命令调用失败: ", e); - return null; + if ("Timed out".equals(e.getMessage())) { + log.error("请求超时: ", e); + throw new BizException("请求超时:1.接口耗时太长,2.服务与客户端失去联系,请重启本服务!详细异常信息:" + e.getMessage()); + } else { + log.error("命令调用失败: ", e); + throw new BizException("命令调用失败:" + e.getMessage()); + } } } @@ -159,42 +170,6 @@ public class WeChatSocketClient { return null; } - /** - * 接收好友请求 - * - * @param v3 xml.attrib["encryptusername"] - * @param v4 xml.attrib["ticket"] - * @return 结果状态码 - */ - public int acceptNewFriend(String v3, String v4) { - int ret = -1; - Verification verification = Verification.newBuilder().setV3(v3).setV4(v4).build(); - Request req = Request.newBuilder().setFuncValue(Functions.FUNC_ACCEPT_FRIEND_VALUE).setV(verification).build(); - Response rsp = sendCmd(req); - if (rsp != null) { - ret = rsp.getStatus(); - } - return ret; - } - - /** - * 添加群成员为微信好友 - * - * @param roomID 群ID - * @param wxIds 要加群的人列表,逗号分隔 - * @return 1 为成功,其他失败 - */ - public int addChatroomMembers(String roomID, String wxIds) { - int ret = -1; - MemberMgmt memberMgmt = MemberMgmt.newBuilder().setRoomid(roomID).setWxids(wxIds).build(); - Request req = Request.newBuilder().setFuncValue(Functions.FUNC_ADD_ROOM_MEMBERS_VALUE).setM(memberMgmt).build(); - Response rsp = sendCmd(req); - if (rsp != null) { - ret = rsp.getStatus(); - } - return ret; - } - /** * 解密图片 * @@ -348,7 +323,16 @@ public class WeChatSocketClient { } } - public void forwardMsg(WxMsg msg, String url) { + /** + * 本机回调解析消息 + * + * @param msg 消息内容 + * @param url 回调地址 + * + * @author chandler + * @date 2024-10-05 12:50 + */ + public void localCallbackAnalyzeMsg(WxMsg msg, String url) { String xml = msg.getXml(); xml = xml.replaceAll(">[\\s\\p{Zs}]*<", "><"); String content = msg.getContent(); @@ -396,10 +380,50 @@ public class WeChatSocketClient { try { String responseStr = HttpClientUtil.doPostJson(url, jsonString); if (!JSONObject.parseObject(responseStr).getString("code").equals("200")) { - log.error("本机消息转发失败!-URL:{}", url); + log.error("本机消息回调失败!-URL:{}", url); } } catch (Exception e) { - log.error("转发接口报错:", e); + log.error("本机消息回调接口报错:", e); + } + } + + /** + * 获取SQL类型 + * + * @param type 转换类型 + * @return 函数 + * + * @author chandler + * @date 2024-10-05 12:54 + */ + public Function getSqlType(int type) { + Map> sqlTypeMap = new HashMap<>(); + // 初始化SQL_TYPES 根据类型执行不同的Func + sqlTypeMap.put(1, bytes -> new String(bytes, StandardCharsets.UTF_8)); + sqlTypeMap.put(2, bytes -> ByteBuffer.wrap(bytes).getFloat()); + sqlTypeMap.put(3, bytes -> new String(bytes, StandardCharsets.UTF_8)); + sqlTypeMap.put(4, bytes -> bytes); + sqlTypeMap.put(5, bytes -> null); + return sqlTypeMap.get(type); + } + + /** + * SQL转换类型 + * + * @param type 转换类型 + * @param content 待转换内容 + * + * @author chandler + * @date 2024-10-05 12:54 + */ + public Object convertSqlVal(int type, ByteString content) { + // 根据每一列的类型转换 + Function converter = getSqlType(type); + if (converter != null) { + return converter.apply(content.toByteArray()); + } else { + log.warn("[SQL转换类型]-未知的SQL类型: {}", type); + return content.toByteArray(); } } diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/service/WeChatDllService.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/service/WeChatDllService.java index b998b8c..3290b42 100644 --- a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/service/WeChatDllService.java +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/service/WeChatDllService.java @@ -2,10 +2,16 @@ package com.wechat.ferry.service; import java.util.List; +import com.wechat.ferry.entity.vo.request.WxPpWcfAddFriendGroupMemberReq; import com.wechat.ferry.entity.vo.request.WxPpWcfDatabaseSqlReq; import com.wechat.ferry.entity.vo.request.WxPpWcfDatabaseTableReq; +import com.wechat.ferry.entity.vo.request.WxPpWcfDeleteGroupMemberReq; import com.wechat.ferry.entity.vo.request.WxPpWcfGroupMemberReq; +import com.wechat.ferry.entity.vo.request.WxPpWcfInviteGroupMemberReq; +import com.wechat.ferry.entity.vo.request.WxPpWcfPassFriendApplyReq; import com.wechat.ferry.entity.vo.request.WxPpWcfPatOnePatMsgReq; +import com.wechat.ferry.entity.vo.request.WxPpWcfReceiveTransferReq; +import com.wechat.ferry.entity.vo.request.WxPpWcfRevokeMsgReq; import com.wechat.ferry.entity.vo.request.WxPpWcfSendEmojiMsgReq; import com.wechat.ferry.entity.vo.request.WxPpWcfSendFileMsgReq; import com.wechat.ferry.entity.vo.request.WxPpWcfSendImageMsgReq; @@ -117,17 +123,6 @@ public interface WeChatDllService { */ List execDbQuerySql(WxPpWcfDatabaseSqlReq request); - /** - * 查询群成员 - * - * @param request 请求入参 - * @return 数据库记录 - * - * @author chandler - * @date 2024-10-02 20:59 - */ - List queryGroupMember(WxPpWcfGroupMemberReq request); - /** * 发送文本消息(可 @) * @@ -207,4 +202,90 @@ public interface WeChatDllService { */ WxPpWcfSendPatOnePatMsgResp patOnePat(WxPpWcfPatOnePatMsgReq request); + /** + * 撤回消息 + * + * @return 结果状态 + * + * @author chandler + * @date 2024-12-25 11:59 + */ + String revokeMsg(WxPpWcfRevokeMsgReq request); + + /** + * 通过好友申请 + * + * @param request 请求入参 + * @return 结果状态 + * + * @author chandler + * @date 2024-12-25 09:38 + */ + String passFriendApply(WxPpWcfPassFriendApplyReq request); + + /** + * 添加群成员为微信好友 + * + * @param request 请求入参 + * @return 结果状态 + * + * @author chandler + * @date 2024-12-25 09:38 + */ + String addFriendGroupMember(WxPpWcfAddFriendGroupMemberReq request); + + /** + * 查询群成员列表 + * + * @param request 请求入参 + * @return 数据库记录 + * + * @author chandler + * @date 2024-10-02 20:59 + */ + List queryGroupMemberList(WxPpWcfGroupMemberReq request); + + /** + * 邀请群成员 + * + * @param request 请求入参 + * @return 结果状态 + * + * @author chandler + * @date 2024-12-25 10:02 + */ + String inviteGroupMember(WxPpWcfInviteGroupMemberReq request); + + /** + * 删除群成员 + * + * @param request 请求入参 + * @return 结果状态 + * + * @author chandler + * @date 2024-12-25 10:03 + */ + String deleteGroupMember(WxPpWcfDeleteGroupMemberReq request); + + /** + * 查询朋友圈 + * + * @return 结果状态 + * + * @author chandler + * @date 2024-12-25 11:11 + */ + String queryFriendCircle(); + + /** + * 接收转账 + * + * @param request 请求入参 + * @return 结果状态 + * + * @author chandler + * @date 2024-12-25 13:48 + */ + String receiveTransfer(WxPpWcfReceiveTransferReq request); + } diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/service/impl/WeChatDllServiceImpl.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/service/impl/WeChatDllServiceImpl.java index 6a2b61c..b9e7ca8 100644 --- a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/service/impl/WeChatDllServiceImpl.java +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/service/impl/WeChatDllServiceImpl.java @@ -1,12 +1,9 @@ package com.wechat.ferry.service.impl; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Function; import javax.annotation.Resource; @@ -17,14 +14,20 @@ import org.springframework.util.ObjectUtils; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; -import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; +import com.wechat.ferry.aggregation.facade.ContactDo; import com.wechat.ferry.config.WeChatFerryProperties; import com.wechat.ferry.entity.proto.Wcf; +import com.wechat.ferry.entity.vo.request.WxPpWcfAddFriendGroupMemberReq; import com.wechat.ferry.entity.vo.request.WxPpWcfDatabaseSqlReq; import com.wechat.ferry.entity.vo.request.WxPpWcfDatabaseTableReq; +import com.wechat.ferry.entity.vo.request.WxPpWcfDeleteGroupMemberReq; import com.wechat.ferry.entity.vo.request.WxPpWcfGroupMemberReq; +import com.wechat.ferry.entity.vo.request.WxPpWcfInviteGroupMemberReq; +import com.wechat.ferry.entity.vo.request.WxPpWcfPassFriendApplyReq; import com.wechat.ferry.entity.vo.request.WxPpWcfPatOnePatMsgReq; +import com.wechat.ferry.entity.vo.request.WxPpWcfReceiveTransferReq; +import com.wechat.ferry.entity.vo.request.WxPpWcfRevokeMsgReq; import com.wechat.ferry.entity.vo.request.WxPpWcfSendEmojiMsgReq; import com.wechat.ferry.entity.vo.request.WxPpWcfSendFileMsgReq; import com.wechat.ferry.entity.vo.request.WxPpWcfSendImageMsgReq; @@ -46,11 +49,10 @@ import com.wechat.ferry.entity.vo.response.WxPpWcfSendRichTextMsgResp; import com.wechat.ferry.entity.vo.response.WxPpWcfSendTextMsgResp; import com.wechat.ferry.entity.vo.response.WxPpWcfSendXmlMsgResp; import com.wechat.ferry.enums.DatabaseNameEnum; -import com.wechat.ferry.enums.MsgFwdTypeEnum; +import com.wechat.ferry.enums.MsgCallbackTypeEnum; import com.wechat.ferry.enums.SexEnum; -import com.wechat.ferry.enums.WxContactsMixedEnum; -import com.wechat.ferry.enums.WxContactsOfficialEnum; import com.wechat.ferry.enums.WxContactsTypeEnum; +import com.wechat.ferry.exception.BizException; import com.wechat.ferry.handle.WeChatSocketClient; import com.wechat.ferry.service.WeChatDllService; import com.wechat.ferry.utils.HttpClientUtil; @@ -80,6 +82,8 @@ public class WeChatDllServiceImpl implements WeChatDllService { @Override public Boolean loginStatus() { long startTime = System.currentTimeMillis(); + // 公共校验 + checkClientStatus(); Boolean status = wechatSocketClient.isLogin(); long endTime = System.currentTimeMillis(); log.info("[查询]-[登录状态]-耗时:{}ms,status:{}", (endTime - startTime), status); @@ -89,6 +93,8 @@ public class WeChatDllServiceImpl implements WeChatDllService { @Override public String queryLoginWeChatUid() { long startTime = System.currentTimeMillis(); + // 公共校验 + checkClientStatus(); String weChatUid = ""; Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_GET_SELF_WXID_VALUE).build(); Wcf.Response rsp = wechatSocketClient.sendCmd(req); @@ -103,6 +109,8 @@ public class WeChatDllServiceImpl implements WeChatDllService { @Override public WxPpWcfLoginInfoResp queryLoginWeChatInfo() { long startTime = System.currentTimeMillis(); + // 公共校验 + checkClientStatus(); WxPpWcfLoginInfoResp resp = new WxPpWcfLoginInfoResp(); Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_GET_USER_INFO_VALUE).build(); Wcf.Response rsp = wechatSocketClient.sendCmd(req); @@ -121,6 +129,8 @@ public class WeChatDllServiceImpl implements WeChatDllService { @Override public List queryMsgTypeList() { long startTime = System.currentTimeMillis(); + // 公共校验 + checkClientStatus(); List list = new ArrayList<>(); Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_GET_MSG_TYPES_VALUE).build(); Wcf.Response rsp = wechatSocketClient.sendCmd(req); @@ -142,6 +152,8 @@ public class WeChatDllServiceImpl implements WeChatDllService { @Override public List queryContactsList() { long startTime = System.currentTimeMillis(); + // 公共校验 + checkClientStatus(); List list = new ArrayList<>(); Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_GET_CONTACTS_VALUE).build(); Wcf.Response rsp = wechatSocketClient.sendCmd(req); @@ -174,38 +186,9 @@ public class WeChatDllServiceImpl implements WeChatDllService { } // 微信类型 if (!ObjectUtils.isEmpty(rpcContact.getWxid())) { - // 官方杂号集合 - Map mixedNoMap = WxContactsMixedEnum.toCodeNameMap(); - mixedNoMap.putAll(convertContactsTypeProperties(weChatFerryProperties.getContactsTypeMixed())); - // 公众号 - Map officialMap = WxContactsOfficialEnum.toCodeNameMap(); - officialMap.putAll(convertContactsTypeProperties(weChatFerryProperties.getContactsTypeOfficial())); - - // 类型判断,存在优先级的,官方杂号优先级高于微信公众号(如果定义重复了,常规禁止重复,手机端和电脑端分类不同) - if (rpcContact.getWxid().endsWith(WxContactsTypeEnum.WORK.getAffix())) { - // 企微 - vo.setType(WxContactsTypeEnum.WORK.getCode()); - vo.setTypeLabel(WxContactsTypeEnum.WORK.getName()); - } else if (rpcContact.getWxid().endsWith(WxContactsTypeEnum.GROUP.getAffix()) || rpcContact.getWxid().endsWith("@im.chatroom")) { - // 群聊 @im.chatroom 这种是很早之前的格式,单独例举 - vo.setType(WxContactsTypeEnum.GROUP.getCode()); - vo.setTypeLabel(WxContactsTypeEnum.GROUP.getName()); - } else if (mixedNoMap.containsKey(rpcContact.getWxid())) { - // 官方杂号 - vo.setType(WxContactsTypeEnum.OFFICIAL_MIXED_NO.getCode()); - vo.setTypeLabel(WxContactsTypeEnum.OFFICIAL_MIXED_NO.getName()); - } else if (rpcContact.getWxid().startsWith(WxContactsTypeEnum.OFFICIAL_ACCOUNT.getAffix())) { - // 微信公众号 - vo.setType(WxContactsTypeEnum.OFFICIAL_ACCOUNT.getCode()); - vo.setTypeLabel(WxContactsTypeEnum.OFFICIAL_ACCOUNT.getName()); - } else if (officialMap.containsKey(rpcContact.getWxid())) { - vo.setType(WxContactsTypeEnum.OFFICIAL_ACCOUNT.getCode()); - vo.setTypeLabel(WxContactsTypeEnum.OFFICIAL_ACCOUNT.getName()); - } else { - // 个微 - vo.setType(WxContactsTypeEnum.PERSON.getCode()); - vo.setTypeLabel(WxContactsTypeEnum.PERSON.getName()); - } + String type = ContactDo.convertContactType(rpcContact.getWxid(), weChatFerryProperties); + vo.setType(type); + vo.setTypeLabel(WxContactsTypeEnum.getCodeMap(rpcContact.getWxid()).getName()); } list.add(vo); } @@ -218,6 +201,8 @@ public class WeChatDllServiceImpl implements WeChatDllService { @Override public List queryDbTableNameList() { long startTime = System.currentTimeMillis(); + // 公共校验 + checkClientStatus(); List list = new ArrayList<>(); Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_GET_DB_NAMES_VALUE).build(); Wcf.Response rsp = wechatSocketClient.sendCmd(req); @@ -232,6 +217,8 @@ public class WeChatDllServiceImpl implements WeChatDllService { @Override public List queryDbTableList(WxPpWcfDatabaseTableReq request) { long startTime = System.currentTimeMillis(); + // 公共校验 + checkClientStatus(); log.info("[查询]-[数据库表列表]-request:{}", request); List list = new ArrayList<>(); Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_GET_DB_TABLES_VALUE).setStr(request.getDatabaseName()).build(); @@ -253,6 +240,8 @@ public class WeChatDllServiceImpl implements WeChatDllService { @Override public List execDbQuerySql(WxPpWcfDatabaseSqlReq request) { long startTime = System.currentTimeMillis(); + // 公共校验 + checkClientStatus(); List list = new ArrayList<>(); List wcfList = wechatSocketClient.querySql(request.getDatabaseName(), request.getSqlText()); if (!CollectionUtils.isEmpty(wcfList)) { @@ -266,7 +255,7 @@ public class WeChatDllServiceImpl implements WeChatDllService { log.warn("未知的SQL类型: {}", dbField.getType()); value = dbField.getContent().toByteArray(); } else { - value = convertSqlVal(dbField.getType(), dbField.getContent()); + value = wechatSocketClient.convertSqlVal(dbField.getType(), dbField.getContent()); } fieldVo.setType(String.valueOf(dbField.getType())); fieldVo.setColumn(dbField.getColumn()); @@ -283,9 +272,219 @@ public class WeChatDllServiceImpl implements WeChatDllService { } @Override - public List queryGroupMember(WxPpWcfGroupMemberReq request) { + public WxPpWcfSendTextMsgResp sendTextMsg(WxPpWcfSendTextMsgReq request) { long startTime = System.currentTimeMillis(); + // 公共校验 + checkClientStatus(); + log.info("[发送消息]-[文本消息]-入参打印:{}", request); + String atUser = ""; + if (request.getIsAtAll()) { + // 艾特全体,仅管理员有效 + atUser = "@all"; + } else { + // 处理艾特的人员 + if (!CollectionUtils.isEmpty(request.getAtUsers())) { + atUser = String.join(",", request.getAtUsers()); + } + } + Wcf.TextMsg textMsg = Wcf.TextMsg.newBuilder().setMsg(request.getMsgText()).setReceiver(request.getRecipient()).setAters(atUser).build(); + Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_SEND_TXT_VALUE).setTxt(textMsg).build(); + log.debug("sendText: {}", wechatSocketClient.bytesToHex(req.toByteArray())); + Wcf.Response rsp = wechatSocketClient.sendCmd(req); + // 0 为成功,其他失败 + int state = judgeWcfCmdState(rsp); + // 回调处理 + String stringJson = JSON.toJSONString(request); + sendMsgCallback(stringJson, state); + long endTime = System.currentTimeMillis(); + log.info("[发送消息]-[文本消息]-处理结束,耗时:{}ms", (endTime - startTime)); + return null; + } + + @Override + public WxPpWcfSendRichTextMsgResp sendRichTextMsg(WxPpWcfSendRichTextMsgReq request) { + long startTime = System.currentTimeMillis(); + // 公共校验 + checkClientStatus(); + log.info("[发送消息]-[富文本消息]-入参打印:{}", request); + Wcf.RichText richTextMsg = Wcf.RichText.newBuilder().setName(request.getName()).setAccount(request.getAccount()).setTitle(request.getTitle()) + .setDigest(request.getDigest()).setUrl(request.getJumpUrl()).setThumburl(request.getThumbnailUrl()).setReceiver(request.getRecipient()) + .build(); + Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_SEND_RICH_TXT_VALUE).setRt(richTextMsg).build(); + log.debug("sendRichText: {}", wechatSocketClient.bytesToHex(req.toByteArray())); + Wcf.Response rsp = wechatSocketClient.sendCmd(req); + int state = judgeWcfCmdState(rsp); + // 回调处理 + String stringJson = JSON.toJSONString(request); + sendMsgCallback(stringJson, state); + long endTime = System.currentTimeMillis(); + log.info("[发送消息]-[富文本消息]-处理结束,耗时:{}ms", (endTime - startTime)); + return null; + } + + @Override + public WxPpWcfSendXmlMsgResp sendXmlMsg(WxPpWcfSendXmlMsgReq request) { + long startTime = System.currentTimeMillis(); + // 公共校验 + checkClientStatus(); + log.info("[发送消息]-[XML消息]-入参打印:{}", request); + int xmlType = 0x21; + if ("21".equals(request.getXmlType())) { + // 小程序 + xmlType = 0x21; + } else { + xmlType = Integer.parseInt(request.getXmlType()); + } + Wcf.XmlMsg xmlMsg = Wcf.XmlMsg.newBuilder().setContent(request.getXmlContent()).setReceiver(request.getRecipient()) + .setPath(request.getResourcePath()).setType(xmlType).build(); + Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_SEND_XML_VALUE).setXml(xmlMsg).build(); + log.debug("sendXml: {}", wechatSocketClient.bytesToHex(req.toByteArray())); + Wcf.Response rsp = wechatSocketClient.sendCmd(req); + int state = judgeWcfCmdState(rsp); + // 回调处理 + String stringJson = JSON.toJSONString(request); + sendMsgCallback(stringJson, state); + long endTime = System.currentTimeMillis(); + log.info("[发送消息]-[XML消息]-处理结束,耗时:{}ms", (endTime - startTime)); + return null; + } + + @Override + public WxPpWcfSendImageMsgResp sendImageMsg(WxPpWcfSendImageMsgReq request) { + long startTime = System.currentTimeMillis(); + // 公共校验 + checkClientStatus(); + log.info("[发送消息]-[图片消息]-入参打印:{}", request); + WxPpWcfSendImageMsgResp resp = new WxPpWcfSendImageMsgResp(); + Wcf.PathMsg pathMsg = Wcf.PathMsg.newBuilder().setPath(request.getResourcePath()).setReceiver(request.getRecipient()).build(); + Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_SEND_IMG_VALUE).setFile(pathMsg).build(); + log.debug("sendImage: {}", wechatSocketClient.bytesToHex(req.toByteArray())); + Wcf.Response rsp = wechatSocketClient.sendCmd(req); + int state = judgeWcfCmdState(rsp); + // 回调处理 + String stringJson = JSON.toJSONString(request); + sendMsgCallback(stringJson, state); + long endTime = System.currentTimeMillis(); + log.info("[发送消息]-[图片消息]-处理结束,耗时:{}ms", (endTime - startTime)); + return null; + } + + @Override + public WxPpWcfSendEmojiMsgResp sendEmojiMsg(WxPpWcfSendEmojiMsgReq request) { + long startTime = System.currentTimeMillis(); + // 公共校验 + checkClientStatus(); + log.info("[发送消息]-[表情消息]-入参打印:{}", request); + Wcf.PathMsg pathMsg = Wcf.PathMsg.newBuilder().setPath(request.getResourcePath()).setReceiver(request.getRecipient()).build(); + Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_SEND_EMOTION_VALUE).setFile(pathMsg).build(); + log.debug("sendEmotion: {}", wechatSocketClient.bytesToHex(req.toByteArray())); + Wcf.Response rsp = wechatSocketClient.sendCmd(req); + int state = judgeWcfCmdState(rsp); + // 回调处理 + String stringJson = JSON.toJSONString(request); + sendMsgCallback(stringJson, state); + long endTime = System.currentTimeMillis(); + log.info("[发送消息]-[表情消息]-处理结束,耗时:{}ms", (endTime - startTime)); + return null; + } + + @Override + public WxPpWcfSendFileMsgResp sendFileMsg(WxPpWcfSendFileMsgReq request) { + long startTime = System.currentTimeMillis(); + // 公共校验 + checkClientStatus(); + log.info("[发送消息]-[文件消息]-入参打印:{}", request); + Wcf.PathMsg pathMsg = Wcf.PathMsg.newBuilder().setPath(request.getResourcePath()).setReceiver(request.getRecipient()).build(); + Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_SEND_FILE_VALUE).setFile(pathMsg).build(); + log.debug("sendFile: {}", wechatSocketClient.bytesToHex(req.toByteArray())); + Wcf.Response rsp = wechatSocketClient.sendCmd(req); + int state = judgeWcfCmdState(rsp); + // 回调处理 + String stringJson = JSON.toJSONString(request); + sendMsgCallback(stringJson, state); + long endTime = System.currentTimeMillis(); + log.info("[发送消息]-[文件消息]-处理结束,耗时:{}ms", (endTime - startTime)); + return null; + } + + @Override + public WxPpWcfSendPatOnePatMsgResp patOnePat(WxPpWcfPatOnePatMsgReq request) { + long startTime = System.currentTimeMillis(); + // 公共校验 + checkClientStatus(); + log.info("[发送消息]-[拍一拍消息]-入参打印:{}", request); + Wcf.PatMsg patMsg = Wcf.PatMsg.newBuilder().setRoomid(request.getRecipient()).setWxid(request.getPatUser()).build(); + Wcf.Request wcfReq = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_SEND_PAT_MSG_VALUE).setPm(patMsg).build(); + Wcf.Response rsp = wechatSocketClient.sendCmd(wcfReq); + int state = judgeWcfCmdState(rsp); + // 回调处理 + String stringJson = JSON.toJSONString(request); + sendMsgCallback(stringJson, state); + long endTime = System.currentTimeMillis(); + log.info("[发送消息]-[拍一拍消息]-处理结束,耗时:{}ms", (endTime - startTime)); + return null; + } + + @Override + public String revokeMsg(WxPpWcfRevokeMsgReq request) { + long startTime = System.currentTimeMillis(); + // 公共校验 + checkClientStatus(); + log.info("[撤回消息]-[消息撤回]-入参打印:{}", request); + long msgId = Long.parseLong(request.getMsgId()); + Wcf.Request wcfReq = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_REVOKE_MSG_VALUE).setUi64(msgId).build(); + Wcf.Response rsp = wechatSocketClient.sendCmd(wcfReq); + int state = judgeWcfCmdState(rsp); + // 回调处理 + String stringJson = JSON.toJSONString(request); + sendMsgCallback(stringJson, state); + long endTime = System.currentTimeMillis(); + log.info("[撤回消息]-[消息撤回]-处理结束,耗时:{}ms", (endTime - startTime)); + return ""; + } + + @Override + public String passFriendApply(WxPpWcfPassFriendApplyReq request) { + long startTime = System.currentTimeMillis(); + // 公共校验 + checkClientStatus(); + log.info("[好友申请]-[通过好友申请]-入参打印:{}", request); + Wcf.Verification verification = Wcf.Verification.newBuilder().setV3(request.getApplicant()).setV4(request.getReviewer()).build(); + Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_ACCEPT_FRIEND_VALUE).setV(verification).build(); + Wcf.Response rsp = wechatSocketClient.sendCmd(req); + int state = judgeWcfCmdState(rsp); + long endTime = System.currentTimeMillis(); + log.info("[好友申请]-[通过好友申请]-处理结束,耗时:{}ms", (endTime - startTime)); + return ""; + } + + @Override + public String addFriendGroupMember(WxPpWcfAddFriendGroupMemberReq request) { + long startTime = System.currentTimeMillis(); + // 公共校验 + checkClientStatus(); + log.info("[添加好友]-[添加群成员为好友]-入参打印:{}", request); + if (CollectionUtils.isEmpty(request.getGroupMembers())) { + log.error("[添加好友]-[添加群成员为好友]-待添加人员为空,本次操作取消"); + return ""; + } + String groupMembersStr = String.join(",", request.getGroupMembers()); + Wcf.MemberMgmt memberMgmt = Wcf.MemberMgmt.newBuilder().setRoomid(request.getGroupNo()).setWxids(groupMembersStr).build(); + Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_ADD_ROOM_MEMBERS_VALUE).setM(memberMgmt).build(); + Wcf.Response rsp = wechatSocketClient.sendCmd(req); + int state = judgeWcfCmdState(rsp); + long endTime = System.currentTimeMillis(); + log.info("[添加好友]-[添加群成员为好友]-处理结束,耗时:{}ms", (endTime - startTime)); + return ""; + } + + @Override + public List queryGroupMemberList(WxPpWcfGroupMemberReq request) { + long startTime = System.currentTimeMillis(); + // 公共校验 + checkClientStatus(); List list = new ArrayList<>(); + String weChatUid = queryLoginWeChatUid(); // 查询群成员 List wcfList = new ArrayList<>(); if (!ObjectUtils.isEmpty(request.getGroupNo())) { @@ -303,11 +502,11 @@ public class WeChatDllServiceImpl implements WeChatDllService { for (Wcf.DbField dbField : dbFieldList) { if ("UserName".equals(dbField.getColumn())) { vo = new WxPpWcfGroupMemberResp(); - String content = (String)convertSqlVal(dbField.getType(), dbField.getContent()); + String content = (String)wechatSocketClient.convertSqlVal(dbField.getType(), dbField.getContent()); vo.setWeChatUid(content); } if ("NickName".equals(dbField.getColumn())) { - String content = (String)convertSqlVal(dbField.getType(), dbField.getContent()); + String content = (String)wechatSocketClient.convertSqlVal(dbField.getType(), dbField.getContent()); vo.setGroupNickName(content); dbMap.put(vo.getWeChatUid(), vo.getGroupNickName()); } @@ -330,6 +529,10 @@ public class WeChatDllServiceImpl implements WeChatDllService { for (Wcf.RoomData.RoomMember member : roomData.getMembersList()) { vo = new WxPpWcfGroupMemberResp(); vo.setWeChatUid(member.getWxid()); + // 是否为自己微信 + vo.setWhetherSelf(weChatUid.equals(member.getWxid())); + // 是否为企微 + vo.setWhetherWork(member.getWxid().endsWith(WxContactsTypeEnum.WORK.getAffix())); String nickName = member.getName(); if (ObjectUtils.isEmpty(nickName)) { // 如果没有设置群昵称则默认为微信名称 @@ -353,207 +556,78 @@ public class WeChatDllServiceImpl implements WeChatDllService { } @Override - public WxPpWcfSendTextMsgResp sendTextMsg(WxPpWcfSendTextMsgReq request) { + public String inviteGroupMember(WxPpWcfInviteGroupMemberReq request) { long startTime = System.currentTimeMillis(); - log.info("[发送消息]-[文本消息]-入参打印:{}", request); - String atUser = ""; - if (request.getIsAtAll()) { - // 艾特全体,仅管理员有效 - atUser = "@all"; - } else { - // 处理艾特的人员 - if (!CollectionUtils.isEmpty(request.getAtUsers())) { - atUser = String.join(",", request.getAtUsers()); - } + // 公共校验 + checkClientStatus(); + log.info("[群成员]-[邀请群成员加入]-入参打印:{}", request); + if (CollectionUtils.isEmpty(request.getGroupMembers())) { + log.error("[群成员]-[邀请群成员加入]-待邀请进群的人员为空,本次操作取消"); + return ""; } - Wcf.TextMsg textMsg = Wcf.TextMsg.newBuilder().setMsg(request.getMsgText()).setReceiver(request.getRecipient()).setAters(atUser).build(); - Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_SEND_TXT_VALUE).setTxt(textMsg).build(); - log.debug("sendText: {}", wechatSocketClient.bytesToHex(req.toByteArray())); + String groupMembersStr = String.join(",", request.getGroupMembers()); + Wcf.MemberMgmt memberMgmt = Wcf.MemberMgmt.newBuilder().setRoomid(request.getGroupNo()).setWxids(groupMembersStr).build(); + Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_INV_ROOM_MEMBERS_VALUE).setM(memberMgmt).build(); Wcf.Response rsp = wechatSocketClient.sendCmd(req); - // 0 为成功,其他失败 - int state = judgeSendMsgState(rsp); - // 转发处理 - String stringJson = JSON.toJSONString(request); - sendMsgForward(stringJson, state); + int state = judgeWcfCmdState(rsp); long endTime = System.currentTimeMillis(); - log.info("[发送消息]-[文本消息]-处理结束,耗时:{}ms", (endTime - startTime)); - return null; + log.info("[群成员]-[邀请群成员加入]-处理结束,耗时:{}ms", (endTime - startTime)); + return ""; } @Override - public WxPpWcfSendRichTextMsgResp sendRichTextMsg(WxPpWcfSendRichTextMsgReq request) { + public String deleteGroupMember(WxPpWcfDeleteGroupMemberReq request) { long startTime = System.currentTimeMillis(); - log.info("[发送消息]-[富文本消息]-入参打印:{}", request); - Wcf.RichText richTextMsg = Wcf.RichText.newBuilder().setName(request.getName()).setAccount(request.getAccount()).setTitle(request.getTitle()) - .setDigest(request.getDigest()).setUrl(request.getJumpUrl()).setThumburl(request.getThumbnailUrl()).setReceiver(request.getRecipient()) - .build(); - Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_SEND_RICH_TXT_VALUE).setRt(richTextMsg).build(); - log.debug("sendRichText: {}", wechatSocketClient.bytesToHex(req.toByteArray())); - Wcf.Response rsp = wechatSocketClient.sendCmd(req); - int state = judgeSendMsgState(rsp); - // 转发处理 - String stringJson = JSON.toJSONString(request); - sendMsgForward(stringJson, state); - long endTime = System.currentTimeMillis(); - log.info("[发送消息]-[富文本消息]-处理结束,耗时:{}ms", (endTime - startTime)); - return null; - } - - @Override - public WxPpWcfSendXmlMsgResp sendXmlMsg(WxPpWcfSendXmlMsgReq request) { - long startTime = System.currentTimeMillis(); - log.info("[发送消息]-[XML消息]-入参打印:{}", request); - int xmlType = 0x21; - if ("21".equals(request.getXmlType())) { - // 小程序 - xmlType = 0x21; + // 公共校验 + checkClientStatus(); + log.info("[群成员]-[删除群成员]-入参打印:{}", request); + if (CollectionUtils.isEmpty(request.getGroupMembers())) { + log.error("[群成员]-[删除群成员]-待删除的人员为空,本次操作取消"); + return ""; } - Wcf.XmlMsg xmlMsg = Wcf.XmlMsg.newBuilder().setContent(request.getXmlContent()).setReceiver(request.getRecipient()) - .setPath(request.getResourcePath()).setType(xmlType).build(); - Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_SEND_XML_VALUE).setXml(xmlMsg).build(); - log.debug("sendXml: {}", wechatSocketClient.bytesToHex(req.toByteArray())); + String groupMembersStr = String.join(",", request.getGroupMembers()); + Wcf.MemberMgmt memberMgmt = Wcf.MemberMgmt.newBuilder().setRoomid(request.getGroupNo()).setWxids(groupMembersStr).build(); + Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_DEL_ROOM_MEMBERS_VALUE).setM(memberMgmt).build(); Wcf.Response rsp = wechatSocketClient.sendCmd(req); - int state = judgeSendMsgState(rsp); - // 转发处理 - String stringJson = JSON.toJSONString(request); - sendMsgForward(stringJson, state); + int state = judgeWcfCmdState(rsp); long endTime = System.currentTimeMillis(); - log.info("[发送消息]-[XML消息]-处理结束,耗时:{}ms", (endTime - startTime)); - return null; + log.info("[群成员]-[删除群成员]-处理结束,耗时:{}ms", (endTime - startTime)); + return ""; } @Override - public WxPpWcfSendImageMsgResp sendImageMsg(WxPpWcfSendImageMsgReq request) { + public String queryFriendCircle() { long startTime = System.currentTimeMillis(); - log.info("[发送消息]-[图片消息]-入参打印:{}", request); - WxPpWcfSendImageMsgResp resp = new WxPpWcfSendImageMsgResp(); - Wcf.PathMsg pathMsg = Wcf.PathMsg.newBuilder().setPath(request.getResourcePath()).setReceiver(request.getRecipient()).build(); - Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_SEND_IMG_VALUE).setFile(pathMsg).build(); - log.debug("sendImage: {}", wechatSocketClient.bytesToHex(req.toByteArray())); + // 公共校验 + checkClientStatus(); + log.info("[查询]-[刷新朋友圈]-开始"); + // id 开始 id,0 为最新页 (string based uint64) + Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_REFRESH_PYQ_VALUE).setUi64(0).build(); Wcf.Response rsp = wechatSocketClient.sendCmd(req); - int state = judgeSendMsgState(rsp); - // 转发处理 - String stringJson = JSON.toJSONString(request); - sendMsgForward(stringJson, state); + int state = judgeWcfCmdState(rsp); long endTime = System.currentTimeMillis(); - log.info("[发送消息]-[图片消息]-处理结束,耗时:{}ms", (endTime - startTime)); - return null; - } - - @Deprecated - @Override - public WxPpWcfSendEmojiMsgResp sendEmojiMsg(WxPpWcfSendEmojiMsgReq request) { - long startTime = System.currentTimeMillis(); - log.info("[发送消息]-[表情消息]-入参打印:{}", request); - Wcf.PathMsg pathMsg = Wcf.PathMsg.newBuilder().setPath(request.getResourcePath()).setReceiver(request.getRecipient()).build(); - Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_SEND_EMOTION_VALUE).setFile(pathMsg).build(); - log.debug("sendEmotion: {}", wechatSocketClient.bytesToHex(req.toByteArray())); - Wcf.Response rsp = wechatSocketClient.sendCmd(req); - int state = judgeSendMsgState(rsp); - // 转发处理 - String stringJson = JSON.toJSONString(request); - sendMsgForward(stringJson, state); - long endTime = System.currentTimeMillis(); - log.info("[发送消息]-[表情消息]-处理结束,耗时:{}ms", (endTime - startTime)); - return null; + log.info("[查询]-[刷新朋友圈]-处理结束,耗时:{}ms", (endTime - startTime)); + return ""; } @Override - public WxPpWcfSendFileMsgResp sendFileMsg(WxPpWcfSendFileMsgReq request) { + public String receiveTransfer(WxPpWcfReceiveTransferReq request) { long startTime = System.currentTimeMillis(); - log.info("[发送消息]-[文件消息]-入参打印:{}", request); - Wcf.PathMsg pathMsg = Wcf.PathMsg.newBuilder().setPath(request.getResourcePath()).setReceiver(request.getRecipient()).build(); - Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_SEND_FILE_VALUE).setFile(pathMsg).build(); - log.debug("sendFile: {}", wechatSocketClient.bytesToHex(req.toByteArray())); + // 公共校验 + checkClientStatus(); + log.info("[转账]-[接收转账]-开始"); + Wcf.Transfer transfer = + Wcf.Transfer.newBuilder().setWxid(request.getWeChatUid()).setTfid(request.getTransferId()).setTaid(request.getTransferId()).build(); + Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_RECV_TRANSFER_VALUE).setTf(transfer).build(); Wcf.Response rsp = wechatSocketClient.sendCmd(req); - int state = judgeSendMsgState(rsp); - // 转发处理 - String stringJson = JSON.toJSONString(request); - sendMsgForward(stringJson, state); + int state = judgeWcfCmdState(rsp); long endTime = System.currentTimeMillis(); - log.info("[发送消息]-[文件消息]-处理结束,耗时:{}ms", (endTime - startTime)); - return null; - } - - @Override - public WxPpWcfSendPatOnePatMsgResp patOnePat(WxPpWcfPatOnePatMsgReq request) { - long startTime = System.currentTimeMillis(); - log.info("[发送消息]-[拍一拍消息]-入参打印:{}", request); - Wcf.PatMsg patMsg = Wcf.PatMsg.newBuilder().setRoomid(request.getRecipient()).setWxid(request.getPatUser()).build(); - Wcf.Request wcfReq = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_SEND_PAT_MSG_VALUE).setPm(patMsg).build(); - Wcf.Response rsp = wechatSocketClient.sendCmd(wcfReq); - int state = judgeSendMsgState(rsp); - // 转发处理 - String stringJson = JSON.toJSONString(request); - sendMsgForward(stringJson, state); - long endTime = System.currentTimeMillis(); - log.info("[发送消息]-[拍一拍消息]-处理结束,耗时:{}ms", (endTime - startTime)); - return null; + log.info("[转账]-[接收转账]-处理结束,耗时:{}ms", (endTime - startTime)); + return ""; } /** - * 获取SQL类型 - * - * @param type 转换类型 - * @return 函数 - * - * @author chandler - * @date 2024-10-05 12:54 - */ - public Function getSqlType(int type) { - Map> sqlTypeMap = new HashMap<>(); - // 初始化SQL_TYPES 根据类型执行不同的Func - sqlTypeMap.put(1, bytes -> ByteBuffer.wrap(bytes).getInt()); - sqlTypeMap.put(2, bytes -> ByteBuffer.wrap(bytes).getFloat()); - sqlTypeMap.put(3, bytes -> new String(bytes, StandardCharsets.UTF_8)); - sqlTypeMap.put(4, bytes -> bytes); - sqlTypeMap.put(5, bytes -> null); - return sqlTypeMap.get(type); - } - - /** - * SQL转换类型 - * - * @param type 转换类型 - * @param content 待转换内容 - * - * @author chandler - * @date 2024-10-05 12:54 - */ - public Object convertSqlVal(int type, ByteString content) { - // 根据每一列的类型转换 - Function converter = getSqlType(type); - if (converter != null) { - return converter.apply(content.toByteArray()); - } else { - log.warn("未知的SQL类型: {}", type); - return content.toByteArray(); - } - } - - /** - * 转换艾特用户 - * - * @param groupNo 群组编号 - * @param atUsers 艾特的用户(名称/微信编号) - * @return 组装后的艾特用户 - * - * @author chandler - * @date 2024-10-03 11:35 - */ - public String dealAtUser(String groupNo, List atUsers) { - String atUserStr = ""; - if (!CollectionUtils.isEmpty(atUsers)) { - // 取出要艾特的用户 - for (String atUser : atUsers) { - - } - } - return atUserStr; - } - - /** - * 消息转发 + * 消息回调 * * @param jsonString json数据 * @param state cmd调用状态 @@ -561,27 +635,27 @@ public class WeChatDllServiceImpl implements WeChatDllService { * @author chandler * @date 2024-10-10 23:10 */ - private void sendMsgForward(String jsonString, Integer state) { - // 根据配置文件决定是否转发 - if (MsgFwdTypeEnum.CLOSE.getCode().equals(weChatFerryProperties.getSendMsgFwdFlag()) - || (MsgFwdTypeEnum.SUCCESS.getCode().equals(weChatFerryProperties.getSendMsgFwdFlag()) && 0 != state)) { - // 如果是关闭 或者 配置为成功才转发但发送状态为失败 的情况则取消发送 + private void sendMsgCallback(String jsonString, Integer state) { + // 根据配置文件决定是否回调 + if (MsgCallbackTypeEnum.CLOSE.getCode().equals(weChatFerryProperties.getSendMsgCallbackFlag()) + || (MsgCallbackTypeEnum.SUCCESS.getCode().equals(weChatFerryProperties.getSendMsgCallbackFlag()) && 0 != state)) { + // 如果是关闭 或者 配置为成功才回调但发送状态为失败 的情况则取消发送 return; } - // 开启转发,且转发地址不为空 - if (!CollectionUtils.isEmpty(weChatFerryProperties.getSendMsgFwdUrls())) { - for (String receiveMsgFwdUrl : weChatFerryProperties.getSendMsgFwdUrls()) { + // 开启回调,且回调地址不为空 + if (!CollectionUtils.isEmpty(weChatFerryProperties.getSendMsgCallbackUrls())) { + for (String receiveMsgFwdUrl : weChatFerryProperties.getSendMsgCallbackUrls()) { if (!receiveMsgFwdUrl.startsWith("http")) { continue; } try { String responseStr = HttpClientUtil.doPostJson(receiveMsgFwdUrl, jsonString); if (judgeSuccess(responseStr)) { - log.error("[发送消息]-消息转发外部接口,获取响应状态失败!-URL:{}", receiveMsgFwdUrl); + log.error("[发送消息]-消息回调至外部接口,获取响应状态失败!-URL:{}", receiveMsgFwdUrl); } - log.debug("[发送消息]-[转发接收到的消息]-转发消息至:{}", receiveMsgFwdUrl); + log.debug("[发送消息]-[回调接收到的消息]-回调消息至:{}", receiveMsgFwdUrl); } catch (Exception e) { - log.error("[发送消息]-消息转发接口[{}]服务异常:", receiveMsgFwdUrl, e); + log.error("[发送消息]-消息回调接口[{}]服务异常:", receiveMsgFwdUrl, e); } } } @@ -615,8 +689,8 @@ public class WeChatDllServiceImpl implements WeChatDllService { } /** - * 判断发送消息状态 - * 0 为成功,其他失败 + * 判断WCF的CMD调用状态 + * 有值 为成功,其他失败 * * @param rsp 响应参数 * @return 状态 @@ -624,8 +698,8 @@ public class WeChatDllServiceImpl implements WeChatDllService { * @author chandler * @date 2024-12-23 21:53 */ - private int judgeSendMsgState(Wcf.Response rsp) { - // 0 为成功,其他失败 + private int judgeWcfCmdState(Wcf.Response rsp) { + // 有值 为成功,其他失败 int state = -1; if (rsp != null) { state = rsp.getStatus(); @@ -660,4 +734,16 @@ public class WeChatDllServiceImpl implements WeChatDllService { return map; } + /** + * 请求前检测客户端状态 + * + * @author chandler + * @date 2025-01-04 18:34 + */ + private void checkClientStatus() { + if (!wechatSocketClient.isLogin()) { + throw new BizException("微信客户端未登录或状态异常,请人工关闭本服务之后,退出微信客户端在重启本服务!"); + } + } + } diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/service/impl/WeChatMsgServiceImpl.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/service/impl/WeChatMsgServiceImpl.java index 640c299..c268777 100644 --- a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/service/impl/WeChatMsgServiceImpl.java +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/service/impl/WeChatMsgServiceImpl.java @@ -4,7 +4,6 @@ import java.util.Map; import javax.annotation.Resource; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; @@ -14,6 +13,8 @@ import com.alibaba.fastjson2.JSONObject; import com.wechat.ferry.config.WeChatFerryProperties; import com.wechat.ferry.entity.dto.WxPpMsgDTO; import com.wechat.ferry.service.WeChatMsgService; +import com.wechat.ferry.strategy.msg.receive.ReceiveMsgFactory; +import com.wechat.ferry.strategy.msg.receive.ReceiveMsgStrategy; import com.wechat.ferry.utils.HttpClientUtil; import lombok.extern.slf4j.Slf4j; @@ -34,34 +35,46 @@ public class WeChatMsgServiceImpl implements WeChatMsgService { @Override public void receiveMsg(String jsonString) { // 转发接口处理 - receiveMsgForward(jsonString); + receiveMsgCallback(jsonString); // 转为JSON对象 WxPpMsgDTO dto = JSON.parseObject(jsonString, WxPpMsgDTO.class); // 有开启的群聊配置 if (!CollectionUtils.isEmpty(weChatFerryProperties.getOpenMsgGroups())) { // 指定处理的群聊 - if (weChatFerryProperties.getOpenMsgGroups().contains(dto.getRoomId())) { - // TODO 这里可以拓展自己需要的功能 + if (weChatFerryProperties.getOpenMsgGroups().contains(dto.getRoomId()) || weChatFerryProperties.getOpenMsgGroups().contains("ALL")) { + // TODO 模式有多种 1-根据消息类型单独调用某一个 2-全部调用,各业务类中自己决定是否继续 + if (true) { + // 因为一种消息允许进行多种处理,这里采用执行所有策略,请自行在各策略中判断是否需要执行 + for (ReceiveMsgStrategy value : ReceiveMsgFactory.getAllStrategyContainers().values()) { + value.doHandle(dto); + } + } else { + // 单独调用某一种 + // 这里自己把消息类型转为自己的枚举类型 + String handleType = "1"; + ReceiveMsgStrategy receiveMsgStrategy = ReceiveMsgFactory.getStrategy(handleType); + receiveMsgStrategy.doHandle(dto); + } } } log.debug("[收到消息]-[消息内容]-打印:{}", dto); } - private void receiveMsgForward(String jsonString) { - // 开启转发,且转发地址不为空 - if (weChatFerryProperties.getReceiveMsgFwdSwitch() && !CollectionUtils.isEmpty(weChatFerryProperties.getReceiveMsgFwdUrls())) { - for (String receiveMsgFwdUrl : weChatFerryProperties.getReceiveMsgFwdUrls()) { + private void receiveMsgCallback(String jsonString) { + // 开启回调,且回调地址不为空 + if (weChatFerryProperties.getReceiveMsgCallbackSwitch() && !CollectionUtils.isEmpty(weChatFerryProperties.getReceiveMsgCallbackUrls())) { + for (String receiveMsgFwdUrl : weChatFerryProperties.getReceiveMsgCallbackUrls()) { if (!receiveMsgFwdUrl.startsWith("http")) { continue; } try { String responseStr = HttpClientUtil.doPostJson(receiveMsgFwdUrl, jsonString); if (judgeSuccess(responseStr)) { - log.error("[接收消息]-消息转发外部接口,获取响应状态失败!-URL:{}", receiveMsgFwdUrl); + log.error("[接收消息]-消息回调至外部接口,获取响应状态失败!-URL:{}", receiveMsgFwdUrl); } - log.debug("[接收消息]-[转发接收到的消息]-转发消息至:{}", receiveMsgFwdUrl); + log.debug("[接收消息]-[回调接收到的消息]-回调消息至:{}", receiveMsgFwdUrl); } catch (Exception e) { - log.error("[接收消息]-消息转发接口[{}]服务异常:", receiveMsgFwdUrl, e); + log.error("[接收消息]-消息回调接口[{}]服务异常:", receiveMsgFwdUrl, e); } } } diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/strategy/.gitkeep b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/strategy/.gitkeep new file mode 100644 index 0000000..a10d4fe --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/strategy/.gitkeep @@ -0,0 +1,3 @@ +# Ignore everything in this directory +* +# Except this file !.gitkeep \ No newline at end of file diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/strategy/msg/receive/ReceiveMsgFactory.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/strategy/msg/receive/ReceiveMsgFactory.java new file mode 100644 index 0000000..39fb5b0 --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/strategy/msg/receive/ReceiveMsgFactory.java @@ -0,0 +1,84 @@ +package com.wechat.ferry.strategy.msg.receive; + +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.Resource; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +import com.wechat.ferry.enums.ReceiveMsgChannelEnum; +import com.wechat.ferry.exception.BizException; + +import lombok.extern.slf4j.Slf4j; + +/** + * 策略Context-消息处理-接收消息 + * 可以切换策略的Context(这里实际是Factory)类 + * + * @author chandler + * @date 2024-12-25 14:08 + */ +@Slf4j +@Component +public class ReceiveMsgFactory implements InitializingBean { + + private static final Map strategyContainerMap = new HashMap<>(); + + /** + * spring的上下文 + */ + @Resource + private ApplicationContext applicationContext; + + /** + * 实现InitializingBean的方法会在启动的时候执行afterPropertiesSet()方法 + * 将Strategy的类都按照定义好的规则(fetchKey),放入Map中 + */ + @Override + public void afterPropertiesSet() { + // 初始化时把所有的策略bean放进ioc,用于使用的时候获取 + Map strategyMap = applicationContext.getBeansOfType(ReceiveMsgStrategy.class); + strategyMap.forEach((k, v) -> { + String type = v.getStrategyType(); + log.debug("[策略Context]-[MessageNoticeSendFactory]-策略类型加载:{}", type); + strategyContainerMap.putIfAbsent(type, v); + }); + } + + /** + * 根据策略类型获取不同处理策略类 + * + * @param strategyType 策略类型 + * @return 策略类 + */ + public static ReceiveMsgStrategy getStrategy(String strategyType) { + log.debug("[策略Context]-[ReceiveMsgStrategy]-当前策略类型:{}", strategyType); + // 策略类对应的枚举 + if (!ReceiveMsgChannelEnum.codeMap.containsKey(strategyType)) { + // 当前的渠道类型未匹配到 + log.error("入参中的策略类型:{}不在枚举(ReceiveMsgChannelEnum)定义范围内,请检查数据合法性!", strategyType); + // TODO 正常所有的策略都应该在枚举中定义,但考虑到有些人是把项目集成到自己系统中,部分自己的策略类未在枚举中定义,所以这里不抛异常,但是我们建议开启 + // throw new BizException("当前策略未在枚举中定义,请先在枚举中指定"); + } + ReceiveMsgStrategy handler = strategyContainerMap.get(strategyType); + if (handler == null) { + log.error("[策略Context]-[MessageNoticeSendFactory]-策略类型:{}-未找到合适的处理器!", strategyType); + throw new BizException("未找到合适的处理器!"); + } + return handler; + } + + /** + * 获取全部策略 + * 用于需要全部执行的情况 + * + * @return 所有的策略类 + */ + public static Map getAllStrategyContainers() { + return strategyContainerMap; + } + +} diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/strategy/msg/receive/ReceiveMsgStrategy.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/strategy/msg/receive/ReceiveMsgStrategy.java new file mode 100644 index 0000000..7fb0a81 --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/strategy/msg/receive/ReceiveMsgStrategy.java @@ -0,0 +1,27 @@ +package com.wechat.ferry.strategy.msg.receive; + +import com.wechat.ferry.entity.dto.WxPpMsgDTO; + +/** + * 策略接口-消息处理-接收消息处理 + * + * @author chandler + * @date 2024-12-25 14:07 + */ +public interface ReceiveMsgStrategy { + + /** + * 获取策略的类型 + * + * @return 返回代表策略类型的字符串 + */ + String getStrategyType(); + + /** + * 具体的处理 + * + * @return 如果是多字段,可以转为JSON字符串返回,已适配不同的返回数据 + */ + String doHandle(WxPpMsgDTO dto); + +} diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/strategy/msg/receive/impl/SignInMsgStrategyImpl.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/strategy/msg/receive/impl/SignInMsgStrategyImpl.java new file mode 100644 index 0000000..7c7061a --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/strategy/msg/receive/impl/SignInMsgStrategyImpl.java @@ -0,0 +1,33 @@ +package com.wechat.ferry.strategy.msg.receive.impl; + +import com.wechat.ferry.entity.dto.WxPpMsgDTO; +import com.wechat.ferry.enums.ReceiveMsgChannelEnum; +import com.wechat.ferry.strategy.msg.receive.ReceiveMsgStrategy; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * 策略实现类-接收消息-签到处理 + * + * @author chandler + * @date 2024-12-25 14:19 + */ +@Slf4j +@Component +public class SignInMsgStrategyImpl implements ReceiveMsgStrategy { + + @Override + public String getStrategyType() { + log.debug("[接收消息]-[签到处理]-匹配到:{}-{}-策略", ReceiveMsgChannelEnum.SIGN_IN.getCode(), ReceiveMsgChannelEnum.SIGN_IN.getName()); + return ReceiveMsgChannelEnum.SIGN_IN.getCode(); + } + + @Override + public String doHandle(WxPpMsgDTO dto) { + // TODO 这里写具体的操作 + // 当前是使用的所有策略类全部执行 所以这里需要控制哪种类型才处理 + log.info("签到处理"); + return ""; + } + +} diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/task/.gitkeep b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/task/.gitkeep new file mode 100644 index 0000000..a10d4fe --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/task/.gitkeep @@ -0,0 +1,3 @@ +# Ignore everything in this directory +* +# Except this file !.gitkeep \ No newline at end of file diff --git a/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/task/ContactGroupMonitorTask.java b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/task/ContactGroupMonitorTask.java new file mode 100644 index 0000000..897d107 --- /dev/null +++ b/clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/task/ContactGroupMonitorTask.java @@ -0,0 +1,193 @@ +package com.wechat.ferry.task; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.annotation.Resource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import com.wechat.ferry.aggregation.facade.ContactDo; +import com.wechat.ferry.config.WeChatFerryProperties; +import com.wechat.ferry.enums.WxContactsTypeEnum; +import com.wechat.ferry.handle.WeChatSocketClient; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +public class ContactGroupMonitorTask { + + private WeChatSocketClient wechatSocketClient; + + @Autowired + public void setWechatSocketClient(WeChatSocketClient wechatSocketClient) { + this.wechatSocketClient = wechatSocketClient; + } + + @Resource + private WeChatFerryProperties weChatFerryProperties; + + /** + * 全部联系人信息集合 key:微信标识-weChatUid val:联系人信息 + */ + private final Map allContactDoMap = new HashMap<>(); + + /** + * 个微联系人信息集合 key:微信标识-weChatUid val:联系人信息 + */ + private final Map ppContactDoMap = new HashMap<>(); + + /** + * 企微联系人信息集合 key:微信标识-weChatUid val:联系人信息 + */ + private final Map cpContactDoMap = new HashMap<>(); + + /** + * 群组信息集合 key:群ID val:群名称 + */ + private final Map groupMap = new HashMap<>(); + + /** + * 群成员信息集合 key:群ID val:微信标识-weChatUid + */ + private final Map> groupMemberMap = new HashMap<>(); + + /** + * 初始化状态 + */ + private Boolean initStatus = false; + + @Scheduled(cron = "0 0 0 * * ?") + public void scheduled() { + if (true) { + // 目前查询的所有的联系人,未判断群组是否已退出等状态,故该功能暂不启用,仅提供一个小样例 + return; + } + ContactDo contactDo = new ContactDo(); + // 查询联系人 + List contactList = contactDo.queryContactListBySql(wechatSocketClient, weChatFerryProperties); + log.info("[定时任务]-[联系人群组监控]-{}", contactList.size()); + // 调用联系人监控处理 + contactMonitor(contactList); + log.info("[定时任务]-[联系人群组监控]-结束"); + } + + // 联系人监控 + private void contactMonitor(List contactList) { + // 新增个微联系人 + List addPpContactList = new ArrayList<>(); + // 删除个微联系人 + List deletePpContactList = new ArrayList<>(); + // 新增企微联系人 + List addCpContactList = new ArrayList<>(); + // 删除企微联系人 + List deleteCpContactList = new ArrayList<>(); + // 新增群组 + List addGroupList = new ArrayList<>(); + // 退出群组 + List deleteGroupList = new ArrayList<>(); + // 本次个微联系人标识列表 + List nowPpContactIdList = new ArrayList<>(); + // 本次企微联系人标识列表 + List nowCpContactIdList = new ArrayList<>(); + // 本次群组标识列表 + List nowGroupIdList = new ArrayList<>(); + + // 开始匹配 + if (!CollectionUtils.isEmpty(contactList)) { + // 判断全部联系人是否为空 + if (allContactDoMap.isEmpty()) { + for (ContactDo contactDo : contactList) { + // 首次初始化 + allContactDoMap.put(contactDo.getWeChatUid(), contactDo); + if (WxContactsTypeEnum.PERSON.getCode().equals(contactDo.getContactType())) { + // 个微-初始化 + ppContactDoMap.put(contactDo.getWeChatUid(), contactDo.getNickname()); + } else if (WxContactsTypeEnum.WORK.getCode().equals(contactDo.getContactType())) { + // 企业微信-初始化 + cpContactDoMap.put(contactDo.getWeChatUid(), contactDo.getNickname()); + } else if (WxContactsTypeEnum.GROUP.getCode().equals(contactDo.getContactType())) { + // 群组-初始化 + groupMap.put(contactDo.getWeChatUid(), contactDo.getNickname()); + } + } + log.info("[定时任务]-[联系人监控]-首次初始化成功"); + } else { + // 检测新增联系人 + for (ContactDo contactDo : contactList) { + if (WxContactsTypeEnum.PERSON.getCode().equals(contactDo.getContactType())) { + // 个微 + nowPpContactIdList.add(contactDo.getWeChatUid()); + if (!ppContactDoMap.containsKey(contactDo.getWeChatUid())) { + // 个微-新增 + addPpContactList.add(contactDo.getWeChatUid()); + ppContactDoMap.put(contactDo.getWeChatUid(), contactDo.getNickname()); + } + } else if (WxContactsTypeEnum.WORK.getCode().equals(contactDo.getContactType())) { + // 企业微信 + nowCpContactIdList.add(contactDo.getWeChatUid()); + if (!cpContactDoMap.containsKey(contactDo.getWeChatUid())) { + // 企业微信-新增 + addCpContactList.add(contactDo.getWeChatUid()); + cpContactDoMap.put(contactDo.getWeChatUid(), contactDo.getNickname()); + } + } else if (WxContactsTypeEnum.GROUP.getCode().equals(contactDo.getContactType())) { + // 群组 + nowGroupIdList.add(contactDo.getWeChatUid()); + if (!groupMap.containsKey(contactDo.getWeChatUid())) { + // 群组-新增 + addGroupList.add(contactDo.getWeChatUid()); + groupMap.put(contactDo.getWeChatUid(), contactDo.getNickname()); + } + } + } + } + + // 初始化完成 + if (initStatus) { + // 个微 + for (Map.Entry entry : ppContactDoMap.entrySet()) { + if (!nowPpContactIdList.contains(entry.getKey())) { + // 个微-删除 + deletePpContactList.add(entry.getKey()); + } + } + // 企微 + for (Map.Entry entry : cpContactDoMap.entrySet()) { + if (!nowCpContactIdList.contains(entry.getKey())) { + // 企微-删除 + deleteCpContactList.add(entry.getKey()); + } + } + // 群组 + for (Map.Entry entry : groupMap.entrySet()) { + if (!nowGroupIdList.contains(entry.getKey())) { + // 群组-删除 + deleteGroupList.add(entry.getKey()); + log.info("\"{}\"离开了群聊"); + } + } + log.info("[定时任务]-[联系人监控]-个微新增:{},个微删除:{},企微新增:{},企微删除:{},群组新增:{},群组删除:{}", addPpContactList, deletePpContactList, addCpContactList, + deleteCpContactList, addGroupList, deleteGroupList); + } + } + initStatus = true; + } + + // 监控群成员 + private void groupMemberMonitor() { + if (!groupMap.isEmpty()) { + List groupIdList = new ArrayList<>(groupMap.keySet()); + for (String groupId : groupIdList) { + // 查询 + } + } + } + +} diff --git a/clients/java/wechat-ferry-mvn/src/main/resources/application.yml b/clients/java/wechat-ferry-mvn/src/main/resources/application.yml index fc9a8c2..8f78100 100644 --- a/clients/java/wechat-ferry-mvn/src/main/resources/application.yml +++ b/clients/java/wechat-ferry-mvn/src/main/resources/application.yml @@ -35,15 +35,15 @@ wechat: # 需要开启消息处理的群 open-msg-groups: - 53257911728@chatroom - # 接收消息转发开关 - receive-msg-fwd-switch: false - # 接收消息转发URL - receive-msg-fwd-urls: + # 接收消息回调开关 + receive-msg-callback-switch: false + # 接收消息回调地址 + receive-msg-callback-urls: - http://localhost:9001/msg - # 发送消息转发标识 1-关闭 2-全转发 3-发送成功才转发 - send-msg-fwd-flag: '1' - # 发送消息转发URL - send-msg-fwd-urls: + # 发送消息回调标识 1-关闭 2-全部回调 3-发送成功才回调 + send-msg-callback-flag: '1' + # 发送消息回调地址 + send-msg-callback-urls: - http://localhost:9001/msg # 调用第三方服务客户端成功状态码 third-party-ok-codes: