Merge pull request #1 from PathfinderAx/develop

自测完毕
This commit is contained in:
chandler 2024-12-24 21:01:48 +08:00 committed by GitHub
commit 720c695aef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 702 additions and 411 deletions

View File

@ -1,10 +1,43 @@
## v39.3.3
### 功能列表
| 接口名 | 地址 | 是否支持 | 备注 |
|----------------|-------------------|------|-------------------|
| 查询登录状态 | /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 | √ | 已测试 |
### 已知BUG
- 1.发送表情微信客户端闪退 - `待修复`
- 2.发送富文本包含thumbnailUrl参数会导致消息发送不出去 - `待修复`
### 2024-12-24
#### ⛰️ Features
- 执行数据库查询SQL请求接口API地址修改
- 业务代码迁移至业务类中,并补充日志信息
- 联系人特殊类型支持配置文件自定义
- 接口入参新增为空校验
- 说明文档更新
- 配置文件有更新
### 2024-12-23
#### ⛰️ Features

View File

@ -53,6 +53,11 @@
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
<!-- 参数校验 -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<!-- swagger3包-->
<dependency>
<groupId>io.springfox</groupId>

View File

@ -48,7 +48,7 @@ public class WeChatConfiguration {
// client.printContacts(client.getContacts());
// 获取数据库
log.info("dbs: {}", wechatSocketClient.getDbNames());
// log.info("dbs: {}", wechatSocketClient.getDbNames());
// 获取数据库下的表
String db = "MicroMsg.db";

View File

@ -29,6 +29,18 @@ public class WeChatFerryProperties {
*/
private Integer socketPort;
/**
* 联系人类型-官方杂号禁止与其他分类重复(格式代码|名称)
* 使用时记得需要提取代码或者名称匹配
*/
private List<String> contactsTypeMixed;
/**
* 联系人类型-公众号禁止与其他分类重复(格式代码|名称)
* 使用时记得需要提取代码或者名称匹配
*/
private List<String> contactsTypeOfficial;
/**
* 需要开启消息处理的群
*/

View File

@ -22,6 +22,7 @@ import com.wechat.ferry.entity.vo.request.WxPpWcfSendTextMsgReq;
import com.wechat.ferry.entity.vo.request.WxPpWcfSendXmlMsgReq;
import com.wechat.ferry.entity.vo.response.WxPpWcfContactsResp;
import com.wechat.ferry.entity.vo.response.WxPpWcfDatabaseRowResp;
import com.wechat.ferry.entity.vo.response.WxPpWcfDatabaseTableResp;
import com.wechat.ferry.entity.vo.response.WxPpWcfGroupMemberResp;
import com.wechat.ferry.entity.vo.response.WxPpWcfLoginInfoResp;
import com.wechat.ferry.entity.vo.response.WxPpWcfMsgTypeResp;
@ -79,46 +80,40 @@ public class WeChatDllController {
return TResponse.ok(ResponseCodeEnum.SUCCESS, resp);
}
@ApiOperation(value = "获取消息类型", notes = "queryMsgTypeList")
@ApiOperation(value = "获取消息类型列表", notes = "queryMsgTypeList")
@PostMapping(value = "/list/msgType")
public TResponse<List<WxPpWcfMsgTypeResp>> queryMsgTypeList() {
List<WxPpWcfMsgTypeResp> list = weChatDllService.queryMsgTypeList();
return TResponse.ok(ResponseCodeEnum.SUCCESS, list);
}
@ApiOperation(value = "获取联系人", notes = "queryContactsList")
@ApiOperation(value = "获取联系人列表", notes = "queryContactsList")
@PostMapping(value = "/list/contacts")
public TResponse<List<WxPpWcfContactsResp>> queryContactsList() {
List<WxPpWcfContactsResp> list = weChatDllService.queryContactsList();
return TResponse.ok(ResponseCodeEnum.SUCCESS, list);
}
@ApiOperation(value = "获取数据库所有表名称", notes = "queryDatabaseAllTableName")
@ApiOperation(value = "获取数据库表名称列表", notes = "queryDbTableNameList")
@PostMapping(value = "/list/dbTableName")
public TResponse<List<String>> queryDatabaseAllTableName() {
List<String> list = weChatDllService.queryDatabaseAllTableName();
public TResponse<List<String>> queryDbTableNameList() {
List<String> list = weChatDllService.queryDbTableNameList();
return TResponse.ok(ResponseCodeEnum.SUCCESS, list);
}
@ApiOperation(value = "获取可查询数据库", notes = "queryDatabaseSql")
@PostMapping(value = "/list/dbSql")
public TResponse<List<WxPpWcfDatabaseRowResp>> queryDatabaseSql(@Validated @RequestBody WxPpWcfDatabaseSqlReq request) {
List<WxPpWcfDatabaseRowResp> list = weChatDllService.queryDatabaseSql(request);
return TResponse.ok(ResponseCodeEnum.SUCCESS, list);
}
@ApiOperation(value = "获取指定数据库中的表", notes = "queryDatabaseTable")
@ApiOperation(value = "获取指定数据库中的表列表", notes = "queryDbTableList")
@PostMapping(value = "/list/dbTable")
public TResponse<List<String>> queryDatabaseTable(@Validated @RequestBody WxPpWcfDatabaseTableReq request) {
List<String> list = weChatDllService.queryDatabaseTable(request);
public TResponse<List<WxPpWcfDatabaseTableResp>> queryDbTableList(@Validated @RequestBody WxPpWcfDatabaseTableReq request) {
List<WxPpWcfDatabaseTableResp> list = weChatDllService.queryDbTableList(request);
return TResponse.ok(ResponseCodeEnum.SUCCESS, list);
}
// @ApiOperation(value = "获取语音消息", notes = "queryMsgTypeList")
// @PostMapping(value = "/list/voiceMsg")
// public TResponse<Object> queryVoiceMsg() {
// return TResponse.ok(ResponseCodeEnum.SUCCESS, list);
// }
@ApiOperation(value = "执行数据库查询SQL", notes = "execDbQuerySql")
@PostMapping(value = "/exec/dbQuerySql")
public TResponse<List<WxPpWcfDatabaseRowResp>> execDbQuerySql(@Validated @RequestBody WxPpWcfDatabaseSqlReq request) {
List<WxPpWcfDatabaseRowResp> list = weChatDllService.execDbQuerySql(request);
return TResponse.ok(ResponseCodeEnum.SUCCESS, list);
}
@ApiOperation(value = "查询群成员", notes = "queryGroupMember")
@PostMapping(value = "/list/groupMember")
@ -130,45 +125,17 @@ public class WeChatDllController {
@ApiOperation(value = "发送消息汇总入口", notes = "sendMsgMaster")
@PostMapping(value = "/send/msgMaster")
public TResponse<WxPpWcfSendTextMsgResp> sendMsgMaster(@Validated @RequestBody String jsonString) {
// todo
return TResponse.ok(ResponseCodeEnum.SUCCESS);
}
@ApiOperation(value = "发送文本消息(可 @", notes = "sendTextMsg")
@ApiOperation(value = "发送文本消息", notes = "sendTextMsg")
@PostMapping(value = "/send/textMsg")
public TResponse<WxPpWcfSendTextMsgResp> sendTextMsg(@Validated @RequestBody WxPpWcfSendTextMsgReq request) {
WxPpWcfSendTextMsgResp resp = weChatDllService.sendTextMsg(request);
return TResponse.ok(ResponseCodeEnum.SUCCESS, resp);
}
@ApiOperation(value = "发送图片消息", notes = "sendImageMsg")
@PostMapping(value = "/send/imageMsg")
public TResponse<WxPpWcfSendImageMsgResp> sendImageMsg(@Validated @RequestBody WxPpWcfSendImageMsgReq request) {
WxPpWcfSendImageMsgResp resp = weChatDllService.sendImageMsg(request);
return TResponse.ok(ResponseCodeEnum.SUCCESS, resp);
}
@ApiOperation(value = "发送文件消息", notes = "sendFileMsg")
@PostMapping(value = "/send/fileMsg")
public TResponse<WxPpWcfSendFileMsgResp> sendFileMsg(@Validated @RequestBody WxPpWcfSendFileMsgReq request) {
WxPpWcfSendFileMsgResp resp = weChatDllService.sendFileMsg(request);
return TResponse.ok(ResponseCodeEnum.SUCCESS, resp);
}
@ApiOperation(value = "发送XML消息", notes = "sendXmlMsg")
@PostMapping(value = "/send/xmlMsg")
public TResponse<WxPpWcfSendXmlMsgResp> sendXmlMsg(@Validated @RequestBody WxPpWcfSendXmlMsgReq request) {
WxPpWcfSendXmlMsgResp resp = weChatDllService.sendXmlMsg(request);
return TResponse.ok(ResponseCodeEnum.SUCCESS, resp);
}
@ApiOperation(value = "发送表情消息", notes = "sendEmojiMsg")
@PostMapping(value = "/send/emojiMsg")
public TResponse<WxPpWcfSendEmojiMsgResp> sendEmojiMsg(@Validated @RequestBody WxPpWcfSendEmojiMsgReq request) {
WxPpWcfSendEmojiMsgResp resp = weChatDllService.sendEmojiMsg(request);
return TResponse.ok(ResponseCodeEnum.SUCCESS, resp);
}
@ApiOperation(value = "发送富文本消息", notes = "sendRichTextMsg")
@PostMapping(value = "/send/richTextMsg")
public TResponse<WxPpWcfSendRichTextMsgResp> sendRichTextMsg(@Validated @RequestBody WxPpWcfSendRichTextMsgReq request) {
@ -176,6 +143,34 @@ public class WeChatDllController {
return TResponse.ok(ResponseCodeEnum.SUCCESS, resp);
}
@ApiOperation(value = "发送XML消息", notes = "sendXmlMsg")
@PostMapping(value = "/send/xmlMsg")
public TResponse<WxPpWcfSendXmlMsgResp> sendXmlMsg(@Validated @RequestBody WxPpWcfSendXmlMsgReq request) {
WxPpWcfSendXmlMsgResp resp = weChatDllService.sendXmlMsg(request);
return TResponse.ok(ResponseCodeEnum.SUCCESS, resp);
}
@ApiOperation(value = "发送图片消息", notes = "sendImageMsg")
@PostMapping(value = "/send/imageMsg")
public TResponse<WxPpWcfSendImageMsgResp> sendImageMsg(@Validated @RequestBody WxPpWcfSendImageMsgReq request) {
WxPpWcfSendImageMsgResp resp = weChatDllService.sendImageMsg(request);
return TResponse.ok(ResponseCodeEnum.SUCCESS, resp);
}
@ApiOperation(value = "发送表情消息", notes = "sendEmojiMsg")
@PostMapping(value = "/send/emojiMsg")
public TResponse<WxPpWcfSendEmojiMsgResp> sendEmojiMsg(@Validated @RequestBody WxPpWcfSendEmojiMsgReq request) {
WxPpWcfSendEmojiMsgResp resp = weChatDllService.sendEmojiMsg(request);
return TResponse.ok(ResponseCodeEnum.SUCCESS, resp);
}
@ApiOperation(value = "发送文件消息", notes = "sendFileMsg")
@PostMapping(value = "/send/fileMsg")
public TResponse<WxPpWcfSendFileMsgResp> sendFileMsg(@Validated @RequestBody WxPpWcfSendFileMsgReq request) {
WxPpWcfSendFileMsgResp resp = weChatDllService.sendFileMsg(request);
return TResponse.ok(ResponseCodeEnum.SUCCESS, resp);
}
@ApiOperation(value = "拍一拍群友", notes = "patOnePat")
@PostMapping(value = "/patOnePat")
public TResponse<WxPpWcfSendPatOnePatMsgResp> patOnePat(@Validated @RequestBody WxPpWcfPatOnePatMsgReq request) {
@ -183,6 +178,12 @@ public class WeChatDllController {
return TResponse.ok(ResponseCodeEnum.SUCCESS, resp);
}
// @ApiOperation(value = "获取语音消息", notes = "queryMsgTypeList")
// @PostMapping(value = "/list/voiceMsg")
// public TResponse<Object> queryVoiceMsg() {
// return TResponse.ok(ResponseCodeEnum.SUCCESS, list);
// }
// @ApiOperation(value = "撤回消息", notes = "queryMsgTypeList")
// @PostMapping(value = "/list/msgType")
// public TResponse<Object> queryMsgTypeList() {

View File

@ -1,5 +1,7 @@
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;
@ -17,12 +19,14 @@ public class WxPpWcfDatabaseSqlReq {
/**
* 数据库名称
*/
@NotBlank(message = "数据库名称不能为空")
@ApiModelProperty(value = "数据库名称")
private String databaseName;
/**
* SQL语句
*/
@NotBlank(message = "SQL语句不能为空")
@ApiModelProperty(value = "SQL语句")
private String sqlText;

View File

@ -1,5 +1,7 @@
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;
@ -17,6 +19,7 @@ public class WxPpWcfDatabaseTableReq {
/**
* 数据库名称
*/
@NotBlank(message = "数据库名称不能为空")
@ApiModelProperty(value = "数据库名称")
private String databaseName;

View File

@ -1,5 +1,7 @@
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;
@ -17,6 +19,7 @@ public class WxPpWcfGroupMemberReq {
/**
* 群编号
*/
@NotBlank(message = "群编号不能为空")
@ApiModelProperty(value = "群编号")
private String groupNo;

View File

@ -1,5 +1,7 @@
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;
@ -19,13 +21,15 @@ public class WxPpWcfPatOnePatMsgReq {
* 消息接收人私聊为 wxidwxid_xxxxxxxxxxxxxx
* 群聊为 roomidxxxxxxxxxx@chatroom
*/
@NotBlank(message = "消息接收人不能为空")
@ApiModelProperty(value = "消息接收人")
private String recipient;
/**
* 要拍的wxid
* 要拍的人的wxid
*/
@ApiModelProperty(value = "要拍的wxid")
@NotBlank(message = "要拍的人的wxid不能为空")
@ApiModelProperty(value = "要拍的人的wxid")
private String patUser;
}

View File

@ -1,5 +1,7 @@
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;
@ -18,6 +20,7 @@ public class WxPpWcfSendEmojiMsgReq {
* 资源路径-本地表情路径
* 需要确保图片路径正确建议使用绝对路径使用双斜杠\\
*/
@NotBlank(message = "资源路径不能为空")
@ApiModelProperty(value = "资源路径-本地表情路径")
private String resourcePath;
@ -26,6 +29,7 @@ public class WxPpWcfSendEmojiMsgReq {
* 消息接收人私聊为 wxidwxid_xxxxxxxxxxxxxx
* 群聊为 roomidxxxxxxxxxx@chatroom
*/
@NotBlank(message = "消息接收人不能为空")
@ApiModelProperty(value = "消息接收人")
private String recipient;

View File

@ -1,5 +1,7 @@
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;
@ -17,6 +19,7 @@ public class WxPpWcfSendFileMsgReq {
/**
* 资源路径-本地文件路径
*/
@NotBlank(message = "资源路径不能为空")
@ApiModelProperty(value = "资源路径-本地文件路径")
private String resourcePath;
@ -25,6 +28,7 @@ public class WxPpWcfSendFileMsgReq {
* 消息接收人私聊为 wxidwxid_xxxxxxxxxxxxxx
* 群聊为 roomidxxxxxxxxxx@chatroom
*/
@NotBlank(message = "消息接收人不能为空")
@ApiModelProperty(value = "消息接收人")
private String recipient;

View File

@ -1,5 +1,7 @@
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;
@ -20,6 +22,7 @@ public class WxPpWcfSendImageMsgReq {
* `C:/Projs/WeChatRobot/TEQuant.jpeg`
* `https://raw.githubusercontent.com/lich0821/WeChatFerry/master/assets/TEQuant.jpg`
*/
@NotBlank(message = "资源路径不能为空")
@ApiModelProperty(value = "资源路径-本地图片地址")
private String resourcePath;
@ -28,6 +31,7 @@ public class WxPpWcfSendImageMsgReq {
* 消息接收人私聊为 wxidwxid_xxxxxxxxxxxxxx
* 群聊为 roomidxxxxxxxxxx@chatroom
*/
@NotBlank(message = "消息接收人不能为空")
@ApiModelProperty(value = "消息接收人")
private String recipient;

View File

@ -4,6 +4,8 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* 请求入参-个微WCF发送富文本消息
*
@ -19,6 +21,7 @@ public class WxPpWcfSendRichTextMsgReq {
* 消息接收人私聊为 wxidwxid_xxxxxxxxxxxxxx
* 群聊为 roomidxxxxxxxxxx@chatroom
*/
@NotBlank(message = "消息接收人不能为空")
@ApiModelProperty(value = "消息接收人")
private String recipient;

View File

@ -1,11 +1,13 @@
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;
import java.util.List;
/**
* 请求入参-个微WCF发送文本消息
*
@ -21,6 +23,7 @@ public class WxPpWcfSendTextMsgReq {
* 消息内容如果是 @ 消息则需要有跟 @ 的人数量相同的 @
* 换行使用 `\\\\n` 单杠
*/
@NotBlank(message = "消息文本不能为空")
@ApiModelProperty(value = "消息文本")
private String msgText;
@ -29,6 +32,7 @@ public class WxPpWcfSendTextMsgReq {
* 消息接收人私聊为 wxidwxid_xxxxxxxxxxxxxx
* 群聊为 roomidxxxxxxxxxx@chatroom
*/
@NotBlank(message = "消息接收人不能为空")
@ApiModelProperty(value = "消息接收人")
private String recipient;

View File

@ -1,5 +1,8 @@
package com.wechat.ferry.entity.vo.request;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ -19,12 +22,14 @@ public class WxPpWcfSendXmlMsgReq {
* 消息接收人私聊为 wxidwxid_xxxxxxxxxxxxxx
* 群聊为 roomidxxxxxxxxxx@chatroom
*/
@NotBlank(message = "消息接收人不能为空")
@ApiModelProperty(value = "消息接收人")
private String recipient;
/**
* XML报文内容
*/
@NotBlank(message = "XML报文内容不能为空")
@ApiModelProperty(value = "XML报文内容")
private String xmlContent;
@ -35,9 +40,10 @@ public class WxPpWcfSendXmlMsgReq {
private String resourcePath;
/**
* xml类型0x21 为小程序
* XML类型21 为小程序
*/
@ApiModelProperty(value = "xml类型")
private Integer xmlType;
@NotNull(message = "XML类型不能为空")
@ApiModelProperty(value = "XML类型")
private String xmlType;
}

View File

@ -30,6 +30,6 @@ public class WxPpWcfDatabaseFieldResp {
* 字段值
*/
@ApiModelProperty(value = "字段值")
private String value;
private Object value;
}

View File

@ -0,0 +1,29 @@
package com.wechat.ferry.entity.vo.response;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 请求出参-个微WCF数据库表
*
* @author chandler
* @date 2024/12/24 13:40
*/
@Data
@ApiModel(value = "wxPpWcfDatabaseRowResp", description = "个微WCF数据库表查询请求出参")
public class WxPpWcfDatabaseTableResp {
/**
* 表名
*/
@ApiModelProperty(value = "表名")
private String tableName;
/**
* SQL
*/
@ApiModelProperty(value = "SQL")
private String sql;
}

View File

@ -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/24 15:10
*/
@Getter
@AllArgsConstructor
public enum DatabaseNameEnum {
/**
* MicroMsg-
*/
MICRO_MSG("MicroMsg.db", ""),
/**
* 未匹配上
*/
UN_MATCH("", null),
// 结束
;
private final String code;
private final String name;
/**
* map集合 keycode val枚举
*/
public static final Map<String, DatabaseNameEnum> codeMap = Arrays.stream(values()).collect(Collectors.toMap(DatabaseNameEnum::getCode, v -> v));
/**
* 根据code获取枚举
*/
public static DatabaseNameEnum getCodeMap(String code) {
return codeMap.getOrDefault(code, UN_MATCH);
}
}

View File

@ -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/24 15:24
*/
@Getter
@AllArgsConstructor
public enum TableNameEnum {
/**
* CONTACT-联系人
*/
CONTACT("Contact", "联系人", ""),
/**
* 未匹配上
*/
UN_MATCH("", null, ""),
// 结束
;
private final String code;
private final String name;
private final String db;
/**
* map集合 keycode val枚举
*/
public static final Map<String, TableNameEnum> codeMap = Arrays.stream(values()).collect(Collectors.toMap(TableNameEnum::getCode, v -> v));
/**
* 根据code获取枚举
*/
public static TableNameEnum getCodeMap(String code) {
return codeMap.getOrDefault(code, UN_MATCH);
}
}

View File

@ -0,0 +1,90 @@
package com.wechat.ferry.enums;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.util.ObjectUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 枚举-微信联系人-官方杂号
*
* @author chandler
* @date 2024/12/24 16:01
*/
@Getter
@AllArgsConstructor
public enum WxContactsMixedEnum {
/**
* fmessage-朋友推荐消息
*/
F_MESSAGE("fmessage", "朋友推荐消息"),
/**
* medianote-语音记事本
*/
MEDIA_NOTE("medianote", "语音记事本"),
/**
* floatbottle-漂流瓶
*/
FLOAT_BOTTLE("floatbottle", "漂流瓶"),
/**
* filehelper-文件传输助手
*/
FILE_HELPER("filehelper", "文件传输助手"),
/**
* newsapp-新闻
*/
NEWS_APP("newsapp", "新闻"),
/**
* newsapp-微信团队
*/
WEI_XIN("weixin", "微信团队"),
/**
* 未匹配上
*/
UN_MATCH("", null),
// 结束
;
private final String code;
private final String name;
/**
* map集合 keycode val枚举
*/
public static final Map<String, WxContactsMixedEnum> codeMap =
Arrays.stream(values()).collect(Collectors.toMap(WxContactsMixedEnum::getCode, v -> v));
/**
* 根据code获取枚举
*/
public static WxContactsMixedEnum getCodeMap(String code) {
return codeMap.getOrDefault(code, UN_MATCH);
}
/**
* map集合 keycode val名称
*/
public static Map<String, String> toCodeNameMap() {
Map<String, String> map = new HashMap<>();
for (WxContactsMixedEnum val : WxContactsMixedEnum.values()) {
if (!ObjectUtils.isEmpty(val.getCode())) {
map.put(val.getCode(), val.getName());
}
}
return map;
}
}

View File

@ -0,0 +1,85 @@
package com.wechat.ferry.enums;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.util.ObjectUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 枚举-微信联系人-公众号
*
* @author chandler
* @date 2024/12/24 16:36
*/
@Getter
@AllArgsConstructor
public enum WxContactsOfficialEnum {
/**
* wxid_2876568766325-应用宝-yingyongbao
*/
YING_YONG_BAO("wxid_2876568766325", "应用宝"),
/**
* wxid_2965349653612-i黑马-iheima
*/
I_HEI_MA("wxid_2965349653612", "i黑马"),
/**
* wxid_4302923029011-丁香医生-DingXiangYiSheng
*/
DING_XIANG_YI_SHENG("wxid_4302923029011", "丁香医生"),
/**
* mphelper-公众平台安全助手
*/
MP_HELPER("mphelper", "公众平台安全助手"),
/**
* weixinguanhaozhushou-微信公众平台-weixingongzhong
*/
WEI_XIN_GONG_ZHONG("weixinguanhaozhushou", "微信公众平台"),
/**
* 未匹配上
*/
UN_MATCH("", null),
// 结束
;
private final String code;
private final String name;
/**
* map集合 keycode val枚举
*/
public static final Map<String, WxContactsOfficialEnum> codeMap =
Arrays.stream(values()).collect(Collectors.toMap(WxContactsOfficialEnum::getCode, v -> v));
/**
* 根据code获取枚举
*/
public static WxContactsOfficialEnum getCodeMap(String code) {
return codeMap.getOrDefault(code, UN_MATCH);
}
/**
* map集合 keycode val名称
*/
public static Map<String, String> toCodeNameMap() {
Map<String, String> map = new HashMap<>();
for (WxContactsOfficialEnum val : WxContactsOfficialEnum.values()) {
if (!ObjectUtils.isEmpty(val.getCode())) {
map.put(val.getCode(), val.getName());
}
}
return map;
}
}

View File

@ -2,9 +2,7 @@ package com.wechat.ferry.handle;
import java.nio.ByteBuffer;
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;
@ -13,20 +11,15 @@ import org.springframework.util.ObjectUtils;
import com.alibaba.fastjson2.JSONObject;
import com.sun.jna.Native;
import com.wechat.ferry.entity.dto.WxPpMsgDTO;
import com.wechat.ferry.entity.proto.Wcf;
import com.wechat.ferry.entity.proto.Wcf.DbQuery;
import com.wechat.ferry.entity.proto.Wcf.DbRow;
import com.wechat.ferry.entity.proto.Wcf.DbTable;
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.RpcContact;
import com.wechat.ferry.entity.proto.Wcf.UserInfo;
import com.wechat.ferry.entity.proto.Wcf.Verification;
import com.wechat.ferry.entity.proto.Wcf.WxMsg;
import com.wechat.ferry.enums.SexEnum;
import com.wechat.ferry.service.SDK;
import com.wechat.ferry.utils.HttpClientUtil;
import com.wechat.ferry.utils.XmlJsonConvertUtil;
@ -149,53 +142,6 @@ public class WeChatSocketClient {
return false;
}
/**
* 获得微信客户端登录的微信ID
*
* @return 微信ID
*/
public String getSelfWxId() {
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_GET_SELF_WXID_VALUE).build();
Response rsp = sendCmd(req);
if (rsp != null) {
return rsp.getStr();
}
return "";
}
/**
* 获取所有消息类型
*
* @return 消息类型集合
*/
public Map<Integer, String> getMsgTypes() {
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_GET_MSG_TYPES_VALUE).build();
Response rsp = sendCmd(req);
if (rsp != null) {
return rsp.getTypes().getTypesMap();
}
return Wcf.MsgTypes.newBuilder().build().getTypesMap();
}
/**
* 获取所有联系人
* "fmessage": "朋友推荐消息",
* "medianote": "语音记事本",
* "floatbottle": "漂流瓶",
* "filehelper": "文件传输助手",
* "newsapp": "新闻",
*
* @return 联系人列表
*/
public List<RpcContact> getContacts() {
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_GET_CONTACTS_VALUE).build();
Response rsp = sendCmd(req);
if (rsp != null) {
return rsp.getContacts().getContactsList();
}
return Wcf.RpcContacts.newBuilder().build().getContactsList();
}
/**
* 获取sql执行结果
*
@ -213,141 +159,6 @@ public class WeChatSocketClient {
return null;
}
/**
* 获取所有数据库名
*
* @return 数据库名称列表
*/
public List<String> getDbNames() {
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_GET_DB_NAMES_VALUE).build();
Response rsp = sendCmd(req);
if (rsp != null) {
return rsp.getDbs().getNamesList();
}
return Wcf.DbNames.newBuilder().build().getNamesList();
}
/**
* 获取指定数据库中的所有表
*
* @param db 数据库名称
* @return 数据库中表列表
*/
public Map<String, String> getDbTables(String db) {
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_GET_DB_TABLES_VALUE).setStr(db).build();
Response rsp = sendCmd(req);
Map<String, String> tables = new HashMap<>();
if (rsp != null) {
for (DbTable tbl : rsp.getTables().getTablesList()) {
tables.put(tbl.getName(), tbl.getSql());
}
}
return tables;
}
/**
* @param msg: 消息内容如果是 @ 消息则需要有跟 @ 的人数量相同的 @
* @param receiver: 消息接收人私聊为 wxidwxid_xxxxxxxxxxxxxx群聊为
* roomidxxxxxxxxxx@chatroom
* @param aters: 群聊时要 @ 的人私聊时为空字符串多个用逗号分隔@所有人
* notify@all必须是群主或者管理员才有权限
* @return int
* @Description 发送文本消息
* @author Changhua
* @example sendText(" Hello @ 某人1 @ 某人2 ", " xxxxxxxx @ chatroom ",
* "wxid_xxxxxxxxxxxxx1,wxid_xxxxxxxxxxxxx2");
*/
public int sendText(String msg, String receiver, String aters) {
Wcf.TextMsg textMsg = Wcf.TextMsg.newBuilder().setMsg(msg).setReceiver(receiver).setAters(aters).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_SEND_TXT_VALUE).setTxt(textMsg).build();
log.debug("sendText: {}", bytesToHex(req.toByteArray()));
Response rsp = sendCmd(req);
int ret = -1;
if (rsp != null) {
ret = rsp.getStatus();
}
return ret;
}
/**
* 发送图片消息
*
* @param path 图片地址
* @param receiver 接收者微信id
* @return 发送结果状态码
*/
public int sendImage(String path, String receiver) {
Wcf.PathMsg pathMsg = Wcf.PathMsg.newBuilder().setPath(path).setReceiver(receiver).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_SEND_IMG_VALUE).setFile(pathMsg).build();
log.debug("sendImage: {}", bytesToHex(req.toByteArray()));
Response rsp = sendCmd(req);
int ret = -1;
if (rsp != null) {
ret = rsp.getStatus();
}
return ret;
}
/**
* 发送文件消息
*
* @param path 文件地址
* @param receiver 接收者微信id
* @return 发送结果状态码
*/
public int sendFile(String path, String receiver) {
Wcf.PathMsg pathMsg = Wcf.PathMsg.newBuilder().setPath(path).setReceiver(receiver).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_SEND_FILE_VALUE).setFile(pathMsg).build();
log.debug("sendFile: {}", bytesToHex(req.toByteArray()));
Response rsp = sendCmd(req);
int ret = -1;
if (rsp != null) {
ret = rsp.getStatus();
}
return ret;
}
/**
* 发送Xml消息
*
* @param receiver 接收者微信id
* @param xml xml内容
* @param path 路径
* @param type 类型
* @return 发送结果状态码
*/
public int sendXml(String receiver, String xml, String path, int type) {
Wcf.XmlMsg xmlMsg = Wcf.XmlMsg.newBuilder().setContent(xml).setReceiver(receiver).setPath(path).setType(type).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_SEND_XML_VALUE).setXml(xmlMsg).build();
log.debug("sendXml: {}", bytesToHex(req.toByteArray()));
Response rsp = sendCmd(req);
int ret = -1;
if (rsp != null) {
ret = rsp.getStatus();
}
return ret;
}
/**
* 发送表情消息
*
* @param path 表情路径
* @param receiver 消息接收者
* @return 发送结果状态码
*/
@Deprecated
public int sendEmotion(String path, String receiver) {
Wcf.PathMsg pathMsg = Wcf.PathMsg.newBuilder().setPath(path).setReceiver(receiver).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_SEND_EMOTION_VALUE).setFile(pathMsg).build();
log.debug("sendEmotion: {}", bytesToHex(req.toByteArray()));
Response rsp = sendCmd(req);
int ret = -1;
if (rsp != null) {
ret = rsp.getStatus();
}
return ret;
}
/**
* 接收好友请求
*
@ -402,20 +213,6 @@ public class WeChatSocketClient {
return ret == 1;
}
/**
* 获取个人信息
*
* @return 个人信息
*/
public UserInfo getUserInfo() {
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_GET_USER_INFO_VALUE).build();
Response rsp = sendCmd(req);
if (rsp != null) {
return rsp.getUi();
}
return null;
}
public boolean getIsReceivingMsg() {
return isReceivingMsg;
}
@ -434,10 +231,11 @@ public class WeChatSocketClient {
*
* @param wxMsgXml XML消息
* @param wxMsgContent 消息内容
* @param selfWxId 自己的微信id
* @return 是否
*/
public boolean isAtMeMsg(String wxMsgXml, String wxMsgContent) {
String format = String.format("<atuserlist><![CDATA[%s]]></atuserlist>", getSelfWxId());
public boolean isAtMeMsg(String wxMsgXml, String wxMsgContent, String selfWxId) {
String format = String.format("<atuserlist><![CDATA[%s]]></atuserlist>", selfWxId);
boolean isAtAll = wxMsgContent.startsWith("@所有人") || wxMsgContent.startsWith("@all");
if (wxMsgXml.contains(format) && !isAtAll) {
return true;
@ -517,21 +315,6 @@ public class WeChatSocketClient {
}
}
public void printContacts(List<RpcContact> contacts) {
for (RpcContact c : contacts) {
int value = c.getGender();
String gender;
if (SexEnum.BOY.getCode().equals(String.valueOf(value))) {
gender = "";
} else if (SexEnum.GIRL.getCode().equals(String.valueOf(value))) {
gender = "";
} else {
gender = "未知";
}
log.info("{}, {}, {}, {}, {}, {}, {}", c.getWxid(), c.getName(), c.getCode(), c.getCountry(), c.getProvince(), c.getCity(), gender);
}
}
public void printWxMsg(WxMsg msg) {
WxPpMsgDTO dto = new WxPpMsgDTO();
dto.setIsSelf(msg.getIsSelf());
@ -551,7 +334,7 @@ public class WeChatSocketClient {
log.info("收到消息: {}", jsonString);
}
private String bytesToHex(byte[] bytes) {
public String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));

View File

@ -14,6 +14,7 @@ import com.wechat.ferry.entity.vo.request.WxPpWcfSendTextMsgReq;
import com.wechat.ferry.entity.vo.request.WxPpWcfSendXmlMsgReq;
import com.wechat.ferry.entity.vo.response.WxPpWcfContactsResp;
import com.wechat.ferry.entity.vo.response.WxPpWcfDatabaseRowResp;
import com.wechat.ferry.entity.vo.response.WxPpWcfDatabaseTableResp;
import com.wechat.ferry.entity.vo.response.WxPpWcfGroupMemberResp;
import com.wechat.ferry.entity.vo.response.WxPpWcfLoginInfoResp;
import com.wechat.ferry.entity.vo.response.WxPpWcfMsgTypeResp;
@ -45,6 +46,7 @@ public interface WeChatDllService {
/**
* 获取登录微信内部识别号UID
* 获得微信客户端登录的微信ID
*
* @return 微信内部识别号UID
*
@ -64,7 +66,7 @@ public interface WeChatDllService {
WxPpWcfLoginInfoResp queryLoginWeChatInfo();
/**
* 获取所有消息类型
* 获取消息类型列表
*
* @return 消息类型列表
*
@ -74,7 +76,7 @@ public interface WeChatDllService {
List<WxPpWcfMsgTypeResp> queryMsgTypeList();
/**
* 获取所有联系人
* 获取联系人列表
*
* @return 联系人列表
*
@ -84,28 +86,17 @@ public interface WeChatDllService {
List<WxPpWcfContactsResp> queryContactsList();
/**
* 获取数据库所有表名称
* 获取数据库表名称列表
*
* @return 数据库名称列表
*
* @author chandler
* @date 2024-10-02 17:53
*/
List<String> queryDatabaseAllTableName();
List<String> queryDbTableNameList();
/**
* 获取可查询数据库
*
* @param request 请求入参
* @return 数据库记录
*
* @author chandler
* @date 2024-10-02 17:52
*/
List<WxPpWcfDatabaseRowResp> queryDatabaseSql(WxPpWcfDatabaseSqlReq request);
/**
* 获取数据库表
* 获取指定数据库中的所有表
*
* @param request 请求入参
* @return 数据库记录
@ -113,7 +104,18 @@ public interface WeChatDllService {
* @author chandler
* @date 2024-10-02 17:52
*/
List<String> queryDatabaseTable(WxPpWcfDatabaseTableReq request);
List<WxPpWcfDatabaseTableResp> queryDbTableList(WxPpWcfDatabaseTableReq request);
/**
* 执行数据库查询SQL
*
* @param request 请求入参
* @return 数据库记录
*
* @author chandler
* @date 2024-10-02 17:52
*/
List<WxPpWcfDatabaseRowResp> execDbQuerySql(WxPpWcfDatabaseSqlReq request);
/**
* 查询群成员
@ -140,26 +142,15 @@ public interface WeChatDllService {
WxPpWcfSendTextMsgResp sendTextMsg(WxPpWcfSendTextMsgReq request);
/**
* 发送图片消息
* 发送富文本消息
*
* @param request 请求入参
* @return 消息发送返回
*
* @author chandler
* @date 2024-10-04 23:06
* @date 2024-10-06 15:48
*/
WxPpWcfSendImageMsgResp sendImageMsg(WxPpWcfSendImageMsgReq request);
/**
* 发送文件消息
*
* @param request 请求入参
* @return 消息发送返回
*
* @author chandler
* @date 2024-10-04 23:15
*/
WxPpWcfSendFileMsgResp sendFileMsg(WxPpWcfSendFileMsgReq request);
WxPpWcfSendRichTextMsgResp sendRichTextMsg(WxPpWcfSendRichTextMsgReq request);
/**
* 发送XML消息
@ -172,6 +163,17 @@ public interface WeChatDllService {
*/
WxPpWcfSendXmlMsgResp sendXmlMsg(WxPpWcfSendXmlMsgReq request);
/**
* 发送图片消息
*
* @param request 请求入参
* @return 消息发送返回
*
* @author chandler
* @date 2024-10-04 23:06
*/
WxPpWcfSendImageMsgResp sendImageMsg(WxPpWcfSendImageMsgReq request);
/**
* 发送表情消息
*
@ -184,15 +186,15 @@ public interface WeChatDllService {
WxPpWcfSendEmojiMsgResp sendEmojiMsg(WxPpWcfSendEmojiMsgReq request);
/**
* 发送富文本消息
* 发送文件消息
*
* @param request 请求入参
* @return 消息发送返回
*
* @author chandler
* @date 2024-10-06 15:48
* @date 2024-10-04 23:15
*/
WxPpWcfSendRichTextMsgResp sendRichTextMsg(WxPpWcfSendRichTextMsgReq request);
WxPpWcfSendFileMsgResp sendFileMsg(WxPpWcfSendFileMsgReq request);
/**
* 拍一拍

View File

@ -3,7 +3,6 @@ package com.wechat.ferry.service.impl;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -35,6 +34,7 @@ import com.wechat.ferry.entity.vo.request.WxPpWcfSendXmlMsgReq;
import com.wechat.ferry.entity.vo.response.WxPpWcfContactsResp;
import com.wechat.ferry.entity.vo.response.WxPpWcfDatabaseFieldResp;
import com.wechat.ferry.entity.vo.response.WxPpWcfDatabaseRowResp;
import com.wechat.ferry.entity.vo.response.WxPpWcfDatabaseTableResp;
import com.wechat.ferry.entity.vo.response.WxPpWcfGroupMemberResp;
import com.wechat.ferry.entity.vo.response.WxPpWcfLoginInfoResp;
import com.wechat.ferry.entity.vo.response.WxPpWcfMsgTypeResp;
@ -45,8 +45,11 @@ import com.wechat.ferry.entity.vo.response.WxPpWcfSendPatOnePatMsgResp;
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.SexEnum;
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 com.wechat.ferry.service.WeChatDllService;
@ -76,37 +79,53 @@ public class WeChatDllServiceImpl implements WeChatDllService {
@Override
public Boolean loginStatus() {
long startTime = System.currentTimeMillis();
Boolean status = wechatSocketClient.isLogin();
log.info("[查询]-[登录状态]-status:{}", status);
long endTime = System.currentTimeMillis();
log.info("[查询]-[登录状态]-耗时:{}msstatus:{}", (endTime - startTime), status);
return status;
}
@Override
public String queryLoginWeChatUid() {
String weChatUid = wechatSocketClient.getSelfWxId();
log.info("[查询]-[登录微信UID]-weChatUid:{}", weChatUid);
long startTime = System.currentTimeMillis();
String weChatUid = "";
Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_GET_SELF_WXID_VALUE).build();
Wcf.Response rsp = wechatSocketClient.sendCmd(req);
if (!ObjectUtils.isEmpty(rsp)) {
weChatUid = rsp.getStr();
}
long endTime = System.currentTimeMillis();
log.info("[查询]-[登录微信UID]-耗时:{}ms weChatUid:{}", (endTime - startTime), weChatUid);
return weChatUid;
}
@Override
public WxPpWcfLoginInfoResp queryLoginWeChatInfo() {
long startTime = System.currentTimeMillis();
WxPpWcfLoginInfoResp resp = new WxPpWcfLoginInfoResp();
Wcf.UserInfo userInfo = wechatSocketClient.getUserInfo();
if (!ObjectUtils.isEmpty(userInfo)) {
Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_GET_USER_INFO_VALUE).build();
Wcf.Response rsp = wechatSocketClient.sendCmd(req);
if (!ObjectUtils.isEmpty(rsp) && !ObjectUtils.isEmpty(rsp.getUi())) {
Wcf.UserInfo userInfo = rsp.getUi();
resp.setWeChatUid(userInfo.getWxid());
resp.setWeChatNickname(userInfo.getName());
resp.setPhone(userInfo.getMobile());
resp.setHomePath(userInfo.getHome());
}
log.info("[查询]-[获取登录微信信息]-resp:{}", resp);
long endTime = System.currentTimeMillis();
log.info("[查询]-[获取登录微信信息]-耗时:{}ms登录信息:{}", (endTime - startTime), resp);
return resp;
}
@Override
public List<WxPpWcfMsgTypeResp> queryMsgTypeList() {
long startTime = System.currentTimeMillis();
List<WxPpWcfMsgTypeResp> list = new ArrayList<>();
Map<Integer, String> msgTypeMap = wechatSocketClient.getMsgTypes();
if (!CollectionUtils.isEmpty(msgTypeMap)) {
Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_GET_MSG_TYPES_VALUE).build();
Wcf.Response rsp = wechatSocketClient.sendCmd(req);
if (!ObjectUtils.isEmpty(rsp)) {
Map<Integer, String> msgTypeMap = rsp.getTypes().getTypesMap();
WxPpWcfMsgTypeResp resp;
for (Map.Entry<Integer, String> entry : msgTypeMap.entrySet()) {
resp = new WxPpWcfMsgTypeResp();
@ -115,15 +134,19 @@ public class WeChatDllServiceImpl implements WeChatDllService {
list.add(resp);
}
}
log.info("[查询]-[所有消息类型]-共查到:{}条", list.size());
long endTime = System.currentTimeMillis();
log.info("[查询]-[所有消息类型]-共查到:{}条,耗时:{}ms", list.size(), (endTime - startTime));
return list;
}
@Override
public List<WxPpWcfContactsResp> queryContactsList() {
long startTime = System.currentTimeMillis();
List<WxPpWcfContactsResp> list = new ArrayList<>();
List<Wcf.RpcContact> rpcContactList = wechatSocketClient.getContacts();
if (!CollectionUtils.isEmpty(rpcContactList)) {
Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_GET_CONTACTS_VALUE).build();
Wcf.Response rsp = wechatSocketClient.sendCmd(req);
if (!ObjectUtils.isEmpty(rsp) && !ObjectUtils.isEmpty(rsp.getContacts()) && !CollectionUtils.isEmpty(rsp.getContacts().getContactsList())) {
List<Wcf.RpcContact> rpcContactList = rsp.getContacts().getContactsList();
for (Wcf.RpcContact rpcContact : rpcContactList) {
WxPpWcfContactsResp vo = new WxPpWcfContactsResp();
vo.setWeChatUid(rpcContact.getWxid());
@ -151,32 +174,14 @@ public class WeChatDllServiceImpl implements WeChatDllService {
}
// 微信类型
if (!ObjectUtils.isEmpty(rpcContact.getWxid())) {
List<String> mixedNoList = new ArrayList<>();
// 朋友推荐消息
mixedNoList.add("fmessage");
// 语音记事本
mixedNoList.add("medianote");
// 漂流瓶
mixedNoList.add("floatbottle");
// 文件传输助手
mixedNoList.add("filehelper");
// 新闻
mixedNoList.add("newsapp");
// 微信团队
mixedNoList.add("weixin");
// 微信支付 wxzhifu
// mixedNoList.add("gh_3dfda90e39d6");
// 微信公开课 wx-gongkaike
// mixedNoList.add("gh_c46cbbfa1de9");
// 微信运动 WeRun-WeChat
// mixedNoList.add("gh_43f2581f6fd6");
// 微信游戏 game
// mixedNoList.add("gh_25d9ac85a4bc");
// 微信开发者
// mixedNoList.add("gh_56fc3b00cc4f");
// 微信搜一搜 wechat_search
// mixedNoList.add("gh_f08f54ae25a4");
// 官方杂号集合
Map<String, String> mixedNoMap = WxContactsMixedEnum.toCodeNameMap();
mixedNoMap.putAll(convertContactsTypeProperties(weChatFerryProperties.getContactsTypeMixed()));
// 公众号
Map<String, String> officialMap = WxContactsOfficialEnum.toCodeNameMap();
officialMap.putAll(convertContactsTypeProperties(weChatFerryProperties.getContactsTypeOfficial()));
// 类型判断,存在优先级的官方杂号优先级高于微信公众号(如果定义重复了常规禁止重复手机端和电脑端分类不同)
if (rpcContact.getWxid().endsWith(WxContactsTypeEnum.WORK.getAffix())) {
// 企微
vo.setType(WxContactsTypeEnum.WORK.getCode());
@ -185,7 +190,7 @@ public class WeChatDllServiceImpl implements WeChatDllService {
// 群聊 @im.chatroom 这种是很早之前的格式单独例举
vo.setType(WxContactsTypeEnum.GROUP.getCode());
vo.setTypeLabel(WxContactsTypeEnum.GROUP.getName());
} else if (mixedNoList.contains(rpcContact.getWxid())) {
} else if (mixedNoMap.containsKey(rpcContact.getWxid())) {
// 官方杂号
vo.setType(WxContactsTypeEnum.OFFICIAL_MIXED_NO.getCode());
vo.setTypeLabel(WxContactsTypeEnum.OFFICIAL_MIXED_NO.getName());
@ -193,14 +198,7 @@ public class WeChatDllServiceImpl implements WeChatDllService {
// 微信公众号
vo.setType(WxContactsTypeEnum.OFFICIAL_ACCOUNT.getCode());
vo.setTypeLabel(WxContactsTypeEnum.OFFICIAL_ACCOUNT.getName());
} else if ("wxid_2876568766325".equals(rpcContact.getWxid()) || "wxid_2965349653612".equals(rpcContact.getWxid())
|| "wxid_4302923029011".equals(rpcContact.getWxid()) || "mphelper".equals(rpcContact.getWxid())
|| "weixinguanhaozhushou".equals(rpcContact.getWxid())) {
// 应用宝 yingyongbao wxid_2876568766325
// i黑马 iheima wxid_2965349653612
// 丁香医生 DingXiangYiSheng wxid_4302923029011
// 公众平台安全助手 mphelper
// 微信公众平台 weixingongzhong weixinguanhaozhushou
} else if (officialMap.containsKey(rpcContact.getWxid())) {
vo.setType(WxContactsTypeEnum.OFFICIAL_ACCOUNT.getCode());
vo.setTypeLabel(WxContactsTypeEnum.OFFICIAL_ACCOUNT.getName());
} else {
@ -212,19 +210,49 @@ public class WeChatDllServiceImpl implements WeChatDllService {
list.add(vo);
}
}
log.info("[查询]-[联系人]-共查到:{}条", list.size());
long endTime = System.currentTimeMillis();
log.info("[查询]-[联系人]-共查到:{}条,耗时:{}ms", list.size(), (endTime - startTime));
return list;
}
@Override
public List<String> queryDatabaseAllTableName() {
List<String> list = wechatSocketClient.getDbNames();
log.info("[查询]-[数据库名称列表]-共查到:{}条", list.size());
public List<String> queryDbTableNameList() {
long startTime = System.currentTimeMillis();
List<String> list = new ArrayList<>();
Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_GET_DB_NAMES_VALUE).build();
Wcf.Response rsp = wechatSocketClient.sendCmd(req);
if (!ObjectUtils.isEmpty(rsp) && !ObjectUtils.isEmpty(rsp.getDbs()) && !CollectionUtils.isEmpty(rsp.getDbs().getNamesList())) {
list = rsp.getDbs().getNamesList();
}
long endTime = System.currentTimeMillis();
log.info("[查询]-[数据库名称列表]-共查到:{}条,耗时:{}ms", list.size(), (endTime - startTime));
return list;
}
@Override
public List<WxPpWcfDatabaseRowResp> queryDatabaseSql(WxPpWcfDatabaseSqlReq request) {
public List<WxPpWcfDatabaseTableResp> queryDbTableList(WxPpWcfDatabaseTableReq request) {
long startTime = System.currentTimeMillis();
log.info("[查询]-[数据库表列表]-request:{}", request);
List<WxPpWcfDatabaseTableResp> list = new ArrayList<>();
Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_GET_DB_TABLES_VALUE).setStr(request.getDatabaseName()).build();
Wcf.Response rsp = wechatSocketClient.sendCmd(req);
if (!ObjectUtils.isEmpty(rsp) && !ObjectUtils.isEmpty(rsp.getTables()) && !CollectionUtils.isEmpty(rsp.getTables().getTablesList())) {
WxPpWcfDatabaseTableResp resp;
for (Wcf.DbTable tbl : rsp.getTables().getTablesList()) {
resp = new WxPpWcfDatabaseTableResp();
resp.setTableName(tbl.getName());
resp.setSql(tbl.getSql());
list.add(resp);
}
}
long endTime = System.currentTimeMillis();
log.info("[查询]-[数据库表列表]-共查到:{}条,耗时:{}ms", list.size(), (endTime - startTime));
return list;
}
@Override
public List<WxPpWcfDatabaseRowResp> execDbQuerySql(WxPpWcfDatabaseSqlReq request) {
long startTime = System.currentTimeMillis();
List<WxPpWcfDatabaseRowResp> list = new ArrayList<>();
List<Wcf.DbRow> wcfList = wechatSocketClient.querySql(request.getDatabaseName(), request.getSqlText());
if (!CollectionUtils.isEmpty(wcfList)) {
@ -233,9 +261,15 @@ public class WeChatDllServiceImpl implements WeChatDllService {
List<WxPpWcfDatabaseFieldResp> fieldVoList = new ArrayList<>();
for (Wcf.DbField dbField : dbRow.getFieldsList()) {
WxPpWcfDatabaseFieldResp fieldVo = new WxPpWcfDatabaseFieldResp();
Object value;
if (ObjectUtils.isEmpty(dbField.getType())) {
log.warn("未知的SQL类型: {}", dbField.getType());
value = dbField.getContent().toByteArray();
} else {
value = convertSqlVal(dbField.getType(), dbField.getContent());
}
fieldVo.setType(String.valueOf(dbField.getType()));
fieldVo.setColumn(dbField.getColumn());
String value = (String)converterSqlVal(dbField.getType(), dbField.getContent());
fieldVo.setValue(value);
fieldVoList.add(fieldVo);
}
@ -243,30 +277,23 @@ public class WeChatDllServiceImpl implements WeChatDllService {
list.add(rowVo);
}
}
log.info("[查询]-[获取可查询数据库]-wcfList:{}", wcfList);
long endTime = System.currentTimeMillis();
log.info("[查询]-[执行数据库查询SQL]-共查到:{}条,耗时:{}ms", list.size(), (endTime - startTime));
return list;
}
@Override
public List<String> queryDatabaseTable(WxPpWcfDatabaseTableReq request) {
log.info("[查询]-[查询表]-request:{}", request);
Map<String, String> wcfMap = wechatSocketClient.getDbTables(request.getDatabaseName());
// TODO 待建模
log.info("[查询]-[查询表]-查到:{}", wcfMap);
return Collections.emptyList();
}
@Override
public List<WxPpWcfGroupMemberResp> queryGroupMember(WxPpWcfGroupMemberReq request) {
long startTime = System.currentTimeMillis();
List<WxPpWcfGroupMemberResp> list = new ArrayList<>();
// 查询群成员
List<Wcf.DbRow> wcfList = new ArrayList<>();
if (!ObjectUtils.isEmpty(request.getGroupNo())) {
wcfList =
wechatSocketClient.querySql("MicroMsg.db", "SELECT RoomData FROM ChatRoom WHERE ChatRoomName = '" + request.getGroupNo() + "';");
wcfList = wechatSocketClient.querySql(DatabaseNameEnum.MICRO_MSG.getCode(),
"SELECT RoomData FROM ChatRoom WHERE ChatRoomName = '" + request.getGroupNo() + "';");
}
// 查询联系人
List<Wcf.DbRow> dbList = wechatSocketClient.querySql("MicroMsg.db", "SELECT UserName, NickName, Type FROM Contact;");
List<Wcf.DbRow> dbList = wechatSocketClient.querySql(DatabaseNameEnum.MICRO_MSG.getCode(), "SELECT UserName, NickName, Type FROM Contact;");
Map<String, String> dbMap = new HashMap<>();
if (!CollectionUtils.isEmpty(dbList)) {
for (Wcf.DbRow dbRow : dbList) {
@ -276,11 +303,11 @@ public class WeChatDllServiceImpl implements WeChatDllService {
for (Wcf.DbField dbField : dbFieldList) {
if ("UserName".equals(dbField.getColumn())) {
vo = new WxPpWcfGroupMemberResp();
String content = (String)converterSqlVal(dbField.getType(), dbField.getContent());
String content = (String)convertSqlVal(dbField.getType(), dbField.getContent());
vo.setWeChatUid(content);
}
if ("NickName".equals(dbField.getColumn())) {
String content = (String)converterSqlVal(dbField.getType(), dbField.getContent());
String content = (String)convertSqlVal(dbField.getType(), dbField.getContent());
vo.setGroupNickName(content);
dbMap.put(vo.getWeChatUid(), vo.getGroupNickName());
}
@ -320,12 +347,14 @@ public class WeChatDllServiceImpl implements WeChatDllService {
}
}
}
log.info("[查询]-[查询群成员]-共查到:{}条", list.size());
long endTime = System.currentTimeMillis();
log.info("[查询]-[查询群成员]-共查到:{}条,耗时:{}ms", list.size(), (endTime - startTime));
return list;
}
@Override
public WxPpWcfSendTextMsgResp sendTextMsg(WxPpWcfSendTextMsgReq request) {
long startTime = System.currentTimeMillis();
log.info("[发送消息]-[文本消息]-入参打印:{}", request);
String atUser = "";
if (request.getIsAtAll()) {
@ -337,85 +366,136 @@ public class WeChatDllServiceImpl implements WeChatDllService {
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 = wechatSocketClient.sendText(request.getMsgText(), request.getRecipient(), atUser);
log.info("[发送消息]-[文本消息]-处理结束");
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 WxPpWcfSendImageMsgResp sendImageMsg(WxPpWcfSendImageMsgReq request) {
WxPpWcfSendImageMsgResp resp = new WxPpWcfSendImageMsgResp();
int state = wechatSocketClient.sendImage(request.getResourcePath(), request.getRecipient());
// 转发处理
String stringJson = JSON.toJSONString(request);
sendMsgForward(stringJson, state);
return null;
}
@Override
public WxPpWcfSendFileMsgResp sendFileMsg(WxPpWcfSendFileMsgReq request) {
int state = wechatSocketClient.sendFile(request.getResourcePath(), request.getRecipient());
public WxPpWcfSendRichTextMsgResp sendRichTextMsg(WxPpWcfSendRichTextMsgReq 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) {
int state = wechatSocketClient.sendXml(request.getRecipient(), request.getXmlContent(), request.getResourcePath(), request.getXmlType());
long startTime = System.currentTimeMillis();
log.info("[发送消息]-[XML消息]-入参打印:{}", request);
int xmlType = 0x21;
if ("21".equals(request.getXmlType())) {
// 小程序
xmlType = 0x21;
}
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 = judgeSendMsgState(rsp);
// 转发处理
String stringJson = JSON.toJSONString(request);
sendMsgForward(stringJson, state);
long endTime = System.currentTimeMillis();
log.info("[发送消息]-[XML消息]-处理结束,耗时:{}ms", (endTime - startTime));
return null;
}
@Override
public WxPpWcfSendImageMsgResp sendImageMsg(WxPpWcfSendImageMsgReq request) {
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()));
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;
}
@Deprecated
@Override
public WxPpWcfSendEmojiMsgResp sendEmojiMsg(WxPpWcfSendEmojiMsgReq request) {
int state = wechatSocketClient.sendEmotion(request.getResourcePath(), request.getRecipient());
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;
}
@Override
public WxPpWcfSendRichTextMsgResp sendRichTextMsg(WxPpWcfSendRichTextMsgReq 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 wcfReq = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_SEND_RICH_TXT_VALUE).setRt(richTextMsg).build();
Wcf.Response rsp = wechatSocketClient.sendCmd(wcfReq);
int state = judgeState(rsp);
public WxPpWcfSendFileMsgResp sendFileMsg(WxPpWcfSendFileMsgReq 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()));
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 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 = judgeState(rsp);
int state = judgeSendMsgState(rsp);
// 转发处理
String stringJson = JSON.toJSONString(request);
sendMsgForward(stringJson, state);
long endTime = System.currentTimeMillis();
log.info("[发送消息]-[拍一拍消息]-处理结束,耗时:{}ms", (endTime - startTime));
return null;
}
/**
* 获取SQL类型
*
* @return 函数
*
* @param type 转换类型
* @return 函数
*
* @author chandler
* @date 2024-10-05 12:54
@ -440,7 +520,7 @@ public class WeChatDllServiceImpl implements WeChatDllService {
* @author chandler
* @date 2024-10-05 12:54
*/
public Object converterSqlVal(int type, ByteString content) {
public Object convertSqlVal(int type, ByteString content) {
// 根据每一列的类型转换
Function<byte[], Object> converter = getSqlType(type);
if (converter != null) {
@ -535,7 +615,8 @@ public class WeChatDllServiceImpl implements WeChatDllService {
}
/**
* 判断CMD调用状态
* 判断发送消息状态
* 0 为成功其他失败
*
* @param rsp 响应参数
* @return 状态
@ -543,7 +624,8 @@ public class WeChatDllServiceImpl implements WeChatDllService {
* @author chandler
* @date 2024-12-23 21:53
*/
private int judgeState(Wcf.Response rsp) {
private int judgeSendMsgState(Wcf.Response rsp) {
// 0 为成功其他失败
int state = -1;
if (rsp != null) {
state = rsp.getStatus();
@ -551,4 +633,31 @@ public class WeChatDllServiceImpl implements WeChatDllService {
return state;
}
/**
* 转换联系人类型配置
*
* @param list 配置参数
* @return map key:code val:name
*
* @author chandler
* @date 2024-12-24 16:55
*/
private Map<String, String> convertContactsTypeProperties(List<String> list) {
Map<String, String> 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;
}
}

View File

@ -26,6 +26,12 @@ wechat:
dll-path: E:\WeChatFerry\clients\java\wechat-ferry-mvn\dll\sdk.dll
# socket端口
socket-port: 10086
# 联系人类型-官方杂号,禁止与其他分类重复(格式:代码|名称)
contacts-type-mixed:
- filehelper|文件传输助手
# 联系人类型-公众号,禁止与其他分类重复(格式:代码|名称)
contacts-type-official:
- weixinguanhaozhushou|微信公众平台
# 需要开启消息处理的群
open-msg-groups:
- 53257911728@chatroom