Merge pull request #246 from PathfinderAx/master
feat(0): [java]-[wechat-ferry-mvn]-基础功能完善
This commit is contained in:
commit
b97d899f02
@ -2,6 +2,9 @@
|
||||
|
||||
⚠️ **只支持 Windows** ⚠️
|
||||
|
||||
`声明:` 本项目是基于 clients/java/wcferry 项目改造,随着时间推进,项目结构和代码规范逐渐产生分离,使用此项目的人员可参考之前的项目
|
||||
我们在开发时请尽量保持注释的完整性,便于阅读维护
|
||||
|
||||
## 快速使用
|
||||
|
||||
### 环境准备
|
||||
@ -20,11 +23,11 @@
|
||||
|
||||
可以直接以WeChatFerry为根目录打开
|
||||
|
||||
或者以WeChatFerry/clients/java/wcferry-mvn为根目录打开
|
||||
或者以WeChatFerry/clients/java/wechat-ferry-mvn为根目录打开
|
||||
|
||||
### 添加Maven
|
||||
|
||||
找到 WeChatFerry/clients/java/wcferry-mvn/pom.xml 文件,右键添加到Maven中,会自动下载依赖
|
||||
找到 WeChatFerry/clients/java/wechat-ferry-mvn/pom.xml 文件,右键添加到Maven中,会自动下载依赖
|
||||
|
||||
### 替换对应版本的dll
|
||||
|
||||
@ -38,16 +41,17 @@
|
||||
|
||||
```yaml
|
||||
# 本服务参数
|
||||
wcferry:
|
||||
# DLL文件位置
|
||||
dll-path: E:\WeChatFerry\clients\java\wcferry-mvn\dll\sdk.dll
|
||||
# socket端口
|
||||
socket-port: 10086
|
||||
wechat:
|
||||
ferry:
|
||||
# DLL文件位置
|
||||
dll-path: E:\WeChatFerry\clients\java\wechat-ferry-mvn\dll\sdk.dll
|
||||
# socket端口
|
||||
socket-port: 10086
|
||||
```
|
||||
|
||||
### 编译运行
|
||||
|
||||
找到 src/main/java/com/iamteer/WcferryApplication.java 类
|
||||
找到 src/main/java/com/wechat/ferry/WeChatFerryApplication.java 类
|
||||
|
||||
直接启动即可
|
||||
|
||||
@ -71,24 +75,29 @@ swagger地址:http://localhost:9201/swagger-ui/index.html
|
||||
### 模块结构
|
||||
|
||||
```
|
||||
wcferry-mvn
|
||||
wechat-ferry-mvn
|
||||
├─dll 核心dll
|
||||
│ ├─sdk.dll sdk文件
|
||||
│ └─readme.txt 本目录说明文件
|
||||
│
|
||||
├─src 源
|
||||
│ ├─main 重启命令
|
||||
│ │ ├─java(com.iamteer) java代码目录
|
||||
│ │ ├─java(com.wechat.ferry) java代码目录
|
||||
│ │ │ ├─config 配置
|
||||
│ │ │ ├─entity 实体
|
||||
│ │ │ ├─runner 运行(程序启动中与启动后的自动化任务都放置于此)
|
||||
│ │ │ ├─entity 聚合模型
|
||||
│ │ │ │ ├─dto DTO模型
|
||||
│ │ │ │ ├─po 实体模型
|
||||
│ │ │ │ └─vo 视图层返回体目录
|
||||
│ │ │ ├─enums 枚举
|
||||
│ │ │ ├─handle 处理层
|
||||
│ │ │ ├─service 业务接口
|
||||
│ │ │ │ └─impl 业务实现类
|
||||
│ │ │ ├─Client.java socket客户端
|
||||
│ │ │ ├─utils 工具类
|
||||
│ │ │ └─WcferryApplication.java 启动类
|
||||
│ │ │
|
||||
│ │ │resources 资源目录
|
||||
│ │ │ ├─libs 本程序内置依赖包
|
||||
│ │ │ ├─proto proto文件
|
||||
│ │ │ ├─proto proto文件(此目录打包将被排除)
|
||||
│ │ │ ├─win32-x86-64 依赖程序
|
||||
│ │ │ ├─application.yml 本程序主配置文件
|
||||
│ │ │ └─logback-spring.xml 日志配置文件
|
||||
@ -105,12 +114,13 @@ wcferry-mvn
|
||||
|
||||
#### 配置参数
|
||||
|
||||
本程序内置参数统一前缀:wcferry 所有自定义本服务的参数请都放置在此前缀下,如:
|
||||
本程序内置参数统一前缀:wechat.ferry 所有自定义本服务的参数请都放置在此前缀下,如:
|
||||
|
||||
```ymal
|
||||
wcferry:
|
||||
# DLL文件位置
|
||||
dll-path: /dll/sdk.dll
|
||||
wechat:
|
||||
ferry:
|
||||
# DLL文件位置
|
||||
dll-path: /dll/sdk.dll
|
||||
```
|
||||
|
||||
#### 生成proto文件
|
||||
@ -129,7 +139,7 @@ wcferry:
|
||||
如:
|
||||
|
||||
```cmd
|
||||
feat(0): [java]-[wcferry-mvn]-基础类目录划分迁移及代码格式
|
||||
feat(0): [java]-[wechat-ferry-mvn]-基础类目录划分迁移及代码格式
|
||||
```
|
||||
|
||||
| 名称 | 版本 |
|
@ -11,10 +11,10 @@
|
||||
<version>2.7.18</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>wcferry-mvn</artifactId>
|
||||
<artifactId>wechat-ferry-mvn</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>wcferry-mvn</name>
|
||||
<description>wcferry客户端Java-Maven版</description>
|
||||
<name>wechat-ferry-mvn</name>
|
||||
<description>WeChatFerry客户端Java-Maven版</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@ -48,6 +48,23 @@
|
||||
<artifactId>springfox-boot-starter</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</dependency>
|
||||
<!-- Alibaba Fastjson -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2</artifactId>
|
||||
<version>2.0.52</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<version>2.1.3</version>
|
||||
</dependency>
|
||||
<!-- httpclient依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.13</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
@ -1,4 +1,4 @@
|
||||
package com.iamteer;
|
||||
package com.wechat.ferry;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
@ -10,10 +10,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
* @date 2024-09-21 12:19
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class WcferryApplication {
|
||||
public class WeChatFerryApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(WcferryApplication.class, args);
|
||||
SpringApplication.run(WeChatFerryApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.iamteer.config;
|
||||
package com.wechat.ferry.config;
|
||||
|
||||
import java.util.Collections;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.iamteer.config;
|
||||
package com.wechat.ferry.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -26,7 +26,7 @@ public class SwaggerConfig {
|
||||
public Docket api() {
|
||||
return new Docket(DocumentationType.SWAGGER_2).select()
|
||||
// 替换为您的Controller所在的包路径
|
||||
.apis(RequestHandlerSelectors.basePackage("com.iamteer.controller"))
|
||||
.apis(RequestHandlerSelectors.basePackage("com.wechat.ferry.controller"))
|
||||
// 地址
|
||||
.paths(PathSelectors.any()).build().apiInfo(apiInfo());
|
||||
}
|
||||
@ -34,7 +34,7 @@ public class SwaggerConfig {
|
||||
private ApiInfo apiInfo() {
|
||||
return new ApiInfoBuilder()
|
||||
// 文档标题
|
||||
.title("Wcferry接口文档")
|
||||
.title("WeChatFerry接口文档")
|
||||
// 文档路径
|
||||
.description("微信机器人底层框架接口文档")
|
||||
// 文档版本
|
@ -1,45 +1,39 @@
|
||||
package com.iamteer.runner;
|
||||
package com.wechat.ferry.config;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.iamteer.Client;
|
||||
import com.iamteer.config.WcferryProperties;
|
||||
import com.wechat.ferry.handle.WeChatSocketClient;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 启动回调-调用微信
|
||||
* 配置类-注入微信客户端
|
||||
*
|
||||
* @author chandler
|
||||
* @date 2024-09-21 12:21
|
||||
* @date 2024-09-30 12:21
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class WechatRunner implements ApplicationRunner {
|
||||
@Configuration
|
||||
public class WeChatConfiguration {
|
||||
|
||||
@Resource
|
||||
private WcferryProperties properties;
|
||||
private WeChatFerryProperties properties;
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) throws Exception {
|
||||
System.out.println(">>>服务启动第一个开始执行的任务<<<<");
|
||||
runWechat();
|
||||
}
|
||||
@Resource
|
||||
private ServerProperties serverProperties;
|
||||
|
||||
private void runWechat() {
|
||||
log.debug("测试:端口:{},地址:{}", properties.getSocketPort(), properties.getDllPath());
|
||||
@Bean
|
||||
public WeChatSocketClient client() {
|
||||
log.debug("[读取配置文件]-端口:{},地址:{}", properties.getSocketPort(), properties.getDllPath());
|
||||
// 连接远程 RPC
|
||||
// Client client = new Client("127.0.0.1", 10086);
|
||||
|
||||
// 本地启动 RPC
|
||||
// Client client = new Client(); // 默认 10086 端口
|
||||
// Client client = new Client(10088,true); // 也可以指定端口
|
||||
|
||||
Client client = new Client(properties.getSocketPort(), properties.getDllPath()); // 默认 10086 端口
|
||||
WeChatSocketClient wechatSocketClient = new WeChatSocketClient(properties.getSocketPort(), properties.getDllPath());
|
||||
|
||||
// 是否已登录
|
||||
// log.info("isLogin: {}", client.isLogin());
|
||||
@ -54,7 +48,7 @@ public class WechatRunner implements ApplicationRunner {
|
||||
// client.printContacts(client.getContacts());
|
||||
|
||||
// 获取数据库
|
||||
log.info("dbs: {}", client.getDbNames());
|
||||
log.info("dbs: {}", wechatSocketClient.getDbNames());
|
||||
|
||||
// 获取数据库下的表
|
||||
String db = "MicroMsg.db";
|
||||
@ -77,19 +71,30 @@ public class WechatRunner implements ApplicationRunner {
|
||||
// 发送表情消息,gif 必须要存在
|
||||
// client.sendEmotion("C:\\Projs\\WeChatFerry\\emo.gif", "filehelper");
|
||||
|
||||
// 使用本机打印
|
||||
String url = "http://localhost:" + serverProperties.getPort() + "/wechat/msg/receive";
|
||||
// 接收消息,并调用 printWxMsg 处理
|
||||
client.enableRecvMsg(100);
|
||||
wechatSocketClient.enableRecvMsg(100);
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
while (client.getIsReceivingMsg()) {
|
||||
client.printWxMsg(client.getMsg());
|
||||
while (wechatSocketClient.getIsReceivingMsg()) {
|
||||
// 只打印
|
||||
// wechatSocketClient.printWxMsg(wechatSocketClient.getMsg());
|
||||
// 转发到boot项目进行消息处理
|
||||
wechatSocketClient.forwardMsg(wechatSocketClient.getMsg(), url);
|
||||
}
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
// client.diableRecvMsg(); // 需要停止时调用
|
||||
|
||||
client.keepRunning();
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
wechatSocketClient.keepRunning();
|
||||
}
|
||||
}).start();
|
||||
|
||||
return wechatSocketClient;
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.iamteer.config;
|
||||
package com.wechat.ferry.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
@ -6,15 +6,15 @@ import org.springframework.stereotype.Component;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 配置文件-wcferry的配置文件
|
||||
* 配置文件-WeChatFerry的配置文件
|
||||
*
|
||||
* @author chandler
|
||||
* @date 2024-09-21 21:35
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "wcferry")
|
||||
public class WcferryProperties {
|
||||
@ConfigurationProperties(prefix = "wechat.ferry")
|
||||
public class WeChatFerryProperties {
|
||||
|
||||
/**
|
||||
* dll文件位置
|
44
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/controller/WeChatDllController.java
vendored
Normal file
44
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/controller/WeChatDllController.java
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
package com.wechat.ferry.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.wechat.ferry.entity.TResponse;
|
||||
import com.wechat.ferry.enums.ResponseCodeEnum;
|
||||
import com.wechat.ferry.service.WeChatDllService;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 控制层-微信DLL处理
|
||||
*
|
||||
* @author chandler
|
||||
* @date 2024-10-01 15:48
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/wechat/cgi/dll")
|
||||
@Api(tags = "微信消息处理-接口")
|
||||
public class WeChatDllController {
|
||||
|
||||
private WeChatDllService weChatDllService;
|
||||
|
||||
@Autowired
|
||||
public void setWeChatDllService(WeChatDllService weChatDllService) {
|
||||
this.weChatDllService = weChatDllService;
|
||||
}
|
||||
|
||||
@ApiOperation(value = "测试", notes = "test")
|
||||
@PostMapping(value = "/test")
|
||||
public TResponse<Object> test(@RequestBody JSONObject jsonData) {
|
||||
|
||||
return TResponse.ok(ResponseCodeEnum.SUCCESS);
|
||||
}
|
||||
|
||||
}
|
43
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/controller/WeChatMsgController.java
vendored
Normal file
43
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/controller/WeChatMsgController.java
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
package com.wechat.ferry.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.wechat.ferry.entity.TResponse;
|
||||
import com.wechat.ferry.enums.ResponseCodeEnum;
|
||||
import com.wechat.ferry.service.WeChatMsgService;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 控制层-微信消息处理
|
||||
*
|
||||
* @author chandler
|
||||
* @date 2024-10-01 14:25
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/wechat/msg")
|
||||
@Api(tags = "微信消息处理-接口")
|
||||
public class WeChatMsgController {
|
||||
|
||||
private WeChatMsgService weChatMsgService;
|
||||
|
||||
@Autowired
|
||||
public void setWeChatMsgService(WeChatMsgService weChatMsgService) {
|
||||
this.weChatMsgService = weChatMsgService;
|
||||
}
|
||||
|
||||
@ApiOperation(value = "接收微信消息", notes = "receiveMsg")
|
||||
@PostMapping(value = "/receive")
|
||||
public TResponse<Object> receiveMsg(@RequestBody String jsonString) {
|
||||
weChatMsgService.receiveMsg(jsonString);
|
||||
return TResponse.ok(ResponseCodeEnum.SUCCESS);
|
||||
}
|
||||
|
||||
}
|
18
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/IResponse.java
vendored
Normal file
18
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/IResponse.java
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
package com.wechat.ferry.entity;
|
||||
|
||||
/**
|
||||
* 返回类接口
|
||||
*/
|
||||
public interface IResponse {
|
||||
|
||||
/**
|
||||
* 状态码
|
||||
*/
|
||||
String getCode();
|
||||
|
||||
/**
|
||||
* 返回信息
|
||||
*/
|
||||
String getMsg();
|
||||
|
||||
}
|
111
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/TResponse.java
vendored
Normal file
111
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/TResponse.java
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
package com.wechat.ferry.entity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.wechat.ferry.enums.ResponseCodeEnum;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 返回类封装
|
||||
*/
|
||||
@Data
|
||||
@ToString
|
||||
@Accessors(chain = true)
|
||||
public class TResponse<T> {
|
||||
|
||||
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
/**
|
||||
* 状态码
|
||||
*/
|
||||
@ApiModelProperty(value = "状态码")
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 返回信息
|
||||
*/
|
||||
@ApiModelProperty(value = "返回信息")
|
||||
private String msg;
|
||||
|
||||
/**
|
||||
* 响应时间
|
||||
*/
|
||||
@ApiModelProperty(value = "响应时间")
|
||||
private String time;
|
||||
|
||||
/**
|
||||
* 响应数据
|
||||
*/
|
||||
@ApiModelProperty(value = "响应数据")
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
private T data;
|
||||
|
||||
/**
|
||||
* 返回类
|
||||
*
|
||||
* @author chandler
|
||||
* @date 2023/4/5 11:31
|
||||
* @param t 返回码类
|
||||
* @param data 返回数据
|
||||
* @return TResponse对象
|
||||
*/
|
||||
public TResponse(IResponse t, T data) {
|
||||
this(t);
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回类
|
||||
*
|
||||
* @author chandler
|
||||
* @date 2023/4/5 11:31
|
||||
* @param t 返回码类
|
||||
* @param msg 返回信息
|
||||
* @return TResponse对象
|
||||
*/
|
||||
public TResponse(IResponse t, String msg) {
|
||||
this.code = t.getCode();
|
||||
this.msg = msg;
|
||||
this.time = LocalDateTime.now().format(FORMATTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回类
|
||||
*
|
||||
* @author chandler
|
||||
* @date 2023/4/5 11:31
|
||||
* @param t 返回码类
|
||||
* @param msg 返回信息
|
||||
* @return TResponse对象
|
||||
*/
|
||||
public TResponse(IResponse t, T data, String msg) {
|
||||
this(t, data);
|
||||
// 重写返回信息-替换默认的信息
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public TResponse(IResponse t) {
|
||||
this.code = t.getCode();
|
||||
this.msg = t.getMsg();
|
||||
this.time = LocalDateTime.now().format(FORMATTER);
|
||||
}
|
||||
|
||||
public static <T> TResponse<T> ok(IResponse t) {
|
||||
return new TResponse<>(t);
|
||||
}
|
||||
|
||||
public static <T> TResponse<T> ok(IResponse t, T data) {
|
||||
return new TResponse<>(t, data);
|
||||
}
|
||||
|
||||
public static <T> TResponse<T> fail(String msg) {
|
||||
return new TResponse<>(ResponseCodeEnum.FAILED, msg);
|
||||
}
|
||||
|
||||
}
|
87
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/dto/WxMsgDTO.java
vendored
Normal file
87
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/entity/dto/WxMsgDTO.java
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
package com.wechat.ferry.entity.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* DTO-微信消息
|
||||
*
|
||||
* @author chandler
|
||||
* @date 2024-09-26 19:56
|
||||
*/
|
||||
@Data
|
||||
public class WxMsgDTO {
|
||||
|
||||
/**
|
||||
* 是否自己发送的
|
||||
*/
|
||||
@ApiModelProperty(value = "是否自己发送的")
|
||||
private Boolean isSelf;
|
||||
|
||||
/**
|
||||
* 是否群消息
|
||||
*/
|
||||
@ApiModelProperty(value = "是否群消息")
|
||||
private Boolean isGroup;
|
||||
|
||||
/**
|
||||
* 消息id
|
||||
*/
|
||||
@ApiModelProperty(value = "消息id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 消息类型
|
||||
*/
|
||||
@ApiModelProperty(value = "消息类型")
|
||||
private Integer type;
|
||||
|
||||
/**
|
||||
* 消息类型
|
||||
*/
|
||||
@ApiModelProperty(value = "消息类型")
|
||||
private Integer ts;
|
||||
|
||||
/**
|
||||
* 群id(如果是群消息的话)
|
||||
*/
|
||||
@ApiModelProperty(value = "群id(如果是群消息的话)")
|
||||
private String roomId;
|
||||
|
||||
/**
|
||||
* 消息内容
|
||||
*/
|
||||
@ApiModelProperty(value = "消息内容")
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 消息发送者
|
||||
*/
|
||||
@ApiModelProperty(value = "消息发送者")
|
||||
private String sender;
|
||||
|
||||
/**
|
||||
* 签名
|
||||
*/
|
||||
@ApiModelProperty(value = "签名")
|
||||
private String sign;
|
||||
|
||||
/**
|
||||
* 缩略图
|
||||
*/
|
||||
@ApiModelProperty(value = "缩略图")
|
||||
private String thumb;
|
||||
|
||||
/**
|
||||
* 附加内容
|
||||
*/
|
||||
@ApiModelProperty(value = "附加内容")
|
||||
private String extra;
|
||||
|
||||
/**
|
||||
* 消息xml
|
||||
*/
|
||||
@ApiModelProperty(value = "消息xml")
|
||||
private String xml;
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
65
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/enums/ResponseCodeEnum.java
vendored
Normal file
65
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/enums/ResponseCodeEnum.java
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
package com.wechat.ferry.enums;
|
||||
|
||||
import com.wechat.ferry.entity.IResponse;
|
||||
|
||||
/**
|
||||
* 枚举-返回类状态码
|
||||
*/
|
||||
public enum ResponseCodeEnum implements IResponse {
|
||||
|
||||
/**
|
||||
* 成功-200
|
||||
*/
|
||||
SUCCESS("200", "请求成功"),
|
||||
|
||||
/**
|
||||
* 参数错误-400
|
||||
*/
|
||||
PARAM_ERROR("400", "参数错误"),
|
||||
|
||||
/**
|
||||
* 401-身份验证失败
|
||||
*/
|
||||
NO_AUTH("401", "身份验证失败"),
|
||||
|
||||
/**
|
||||
* 403-您无权访问此资源
|
||||
*/
|
||||
UNAUTHORIZED("403", "您无权访问此资源"),
|
||||
|
||||
/**
|
||||
* 404-未找到该资源
|
||||
*/
|
||||
NOT_FOUND("404", "未找到该资源"),
|
||||
|
||||
/**
|
||||
* 失败-500
|
||||
*/
|
||||
FAILED("500", "请求失败"),
|
||||
|
||||
;
|
||||
|
||||
private final String code;
|
||||
private final String msg;
|
||||
|
||||
ResponseCodeEnum(String code, String msg) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name() + "{" + code + '|' + msg + "}";
|
||||
}
|
||||
|
||||
}
|
42
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/enums/SexEnum.java
vendored
Normal file
42
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/enums/SexEnum.java
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
package com.wechat.ferry.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 枚举-性别
|
||||
*
|
||||
* @author chandler
|
||||
* @date 2024/10/01 15:42
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum SexEnum {
|
||||
|
||||
/**
|
||||
* 0-未知
|
||||
*/
|
||||
UNKNOWN("0", "未知"),
|
||||
|
||||
/**
|
||||
* 1-男
|
||||
*/
|
||||
BOY("1", "男"),
|
||||
|
||||
/**
|
||||
* 2-女
|
||||
*/
|
||||
GIRL("2", "女"),
|
||||
|
||||
/**
|
||||
* 未匹配上
|
||||
*/
|
||||
UN_MATCH("", null),
|
||||
|
||||
// 结束
|
||||
;
|
||||
|
||||
private final String code;
|
||||
private final String name;
|
||||
|
||||
}
|
32
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/enums/WeChatMsgTypeEnum.java
vendored
Normal file
32
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/enums/WeChatMsgTypeEnum.java
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
package com.wechat.ferry.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 枚举-消息类型
|
||||
*
|
||||
* @author chandler
|
||||
* @date 2024/10/01 15:55
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum WeChatMsgTypeEnum {
|
||||
|
||||
/**
|
||||
* 0-未知
|
||||
*/
|
||||
UNKNOWN("0", "未知"),
|
||||
|
||||
/**
|
||||
* 未匹配上
|
||||
*/
|
||||
UN_MATCH("", null),
|
||||
|
||||
// 结束
|
||||
;
|
||||
|
||||
private final String code;
|
||||
private final String name;
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.iamteer;
|
||||
package com.wechat.ferry.handle;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
@ -8,66 +8,90 @@ import java.util.Map;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
import com.iamteer.service.SDK;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.iamteer.entity.Wcf;
|
||||
import com.iamteer.entity.Wcf.DbQuery;
|
||||
import com.iamteer.entity.Wcf.DbRow;
|
||||
import com.iamteer.entity.Wcf.DbTable;
|
||||
import com.iamteer.entity.Wcf.DecPath;
|
||||
import com.iamteer.entity.Wcf.Functions;
|
||||
import com.iamteer.entity.Wcf.MemberMgmt;
|
||||
import com.iamteer.entity.Wcf.Request;
|
||||
import com.iamteer.entity.Wcf.Response;
|
||||
import com.iamteer.entity.Wcf.RpcContact;
|
||||
import com.iamteer.entity.Wcf.UserInfo;
|
||||
import com.iamteer.entity.Wcf.Verification;
|
||||
import com.iamteer.entity.Wcf.WxMsg;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.sun.jna.Native;
|
||||
import com.wechat.ferry.entity.dto.WxMsgDTO;
|
||||
import com.wechat.ferry.entity.po.Wcf;
|
||||
import com.wechat.ferry.entity.po.Wcf.DbQuery;
|
||||
import com.wechat.ferry.entity.po.Wcf.DbRow;
|
||||
import com.wechat.ferry.entity.po.Wcf.DbTable;
|
||||
import com.wechat.ferry.entity.po.Wcf.DecPath;
|
||||
import com.wechat.ferry.entity.po.Wcf.Functions;
|
||||
import com.wechat.ferry.entity.po.Wcf.MemberMgmt;
|
||||
import com.wechat.ferry.entity.po.Wcf.Request;
|
||||
import com.wechat.ferry.entity.po.Wcf.Response;
|
||||
import com.wechat.ferry.entity.po.Wcf.RpcContact;
|
||||
import com.wechat.ferry.entity.po.Wcf.UserInfo;
|
||||
import com.wechat.ferry.entity.po.Wcf.Verification;
|
||||
import com.wechat.ferry.entity.po.Wcf.WxMsg;
|
||||
import com.wechat.ferry.enums.SexEnum;
|
||||
import com.wechat.ferry.service.SDK;
|
||||
import com.wechat.ferry.utils.HttpClientUtil;
|
||||
|
||||
import io.sisu.nng.Socket;
|
||||
import io.sisu.nng.pair.Pair1Socket;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
public class Client {
|
||||
/**
|
||||
* 处理层-微信客户端
|
||||
*
|
||||
* @author Changhua
|
||||
* @date 2023-12-06 22:11
|
||||
*/
|
||||
@Slf4j
|
||||
public class WeChatSocketClient {
|
||||
|
||||
/**
|
||||
* 消息缓冲区大小,16M
|
||||
*/
|
||||
private static final Integer BUFFER_SIZE = 16 * 1024 * 1024;
|
||||
|
||||
/**
|
||||
* 默认IP
|
||||
*/
|
||||
private static final String DEFAULT_HOST = "127.0.0.1";
|
||||
|
||||
/**
|
||||
* 请求地址
|
||||
*/
|
||||
private static final String CMD_URL = "tcp://%s:%s";
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(Client.class);
|
||||
private static final int BUFFER_SIZE = 16 * 1024 * 1024; // 16M
|
||||
private Socket cmdSocket = null;
|
||||
private Socket msgSocket = null;
|
||||
private static String DEFAULT_HOST = "127.0.0.1";
|
||||
private static int PORT = 10086;
|
||||
private static String CMDURL = "tcp://%s:%s";
|
||||
private static String DEFAULT_DLL_PATH = System.getProperty("user.dir") + "\\dll\\sdk.dll";
|
||||
|
||||
/**
|
||||
* 是否收到消息
|
||||
*/
|
||||
private boolean isReceivingMsg = false;
|
||||
|
||||
/**
|
||||
* 是否为本地端口
|
||||
*/
|
||||
private boolean isLocalHostPort = false;
|
||||
|
||||
/**
|
||||
* 消息返回
|
||||
*/
|
||||
private BlockingQueue<WxMsg> msgQ;
|
||||
|
||||
private String host;
|
||||
private int port;
|
||||
private String dllPath;
|
||||
private final String host;
|
||||
private final Integer port;
|
||||
|
||||
public Client() {
|
||||
this(DEFAULT_HOST, PORT, false, DEFAULT_DLL_PATH);
|
||||
}
|
||||
|
||||
public Client(int port, String dllPath) {
|
||||
public WeChatSocketClient(Integer port, String dllPath) {
|
||||
this(DEFAULT_HOST, port, false, dllPath);
|
||||
}
|
||||
|
||||
public Client(String host, int port, boolean debug, String dllPath) {
|
||||
public WeChatSocketClient(String host, Integer port, boolean debug, String dllPath) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.dllPath = dllPath;
|
||||
|
||||
SDK INSTANCE = Native.load(dllPath, SDK.class);
|
||||
int status = INSTANCE.WxInitSDK(debug, port);
|
||||
if (status != 0) {
|
||||
logger.error("启动 RPC 失败: {}", status);
|
||||
log.error("启动 RPC 失败: {}", status);
|
||||
System.exit(-1);
|
||||
}
|
||||
connectRPC(String.format(CMDURL, host, port), INSTANCE);
|
||||
connectRPC(String.format(CMD_URL, host, port), INSTANCE);
|
||||
if (DEFAULT_HOST.equals(host) || "localhost".equalsIgnoreCase(host)) {
|
||||
isLocalHostPort = true;
|
||||
}
|
||||
@ -77,16 +101,16 @@ public class Client {
|
||||
try {
|
||||
cmdSocket = new Pair1Socket();
|
||||
cmdSocket.dial(url);
|
||||
// logger.info("请点击登录微信");
|
||||
while (!isLogin()) { // 直到登录成功
|
||||
while (!isLogin()) {
|
||||
// 直到登录成功
|
||||
waitMs(1000);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("连接 RPC 失败: ", e);
|
||||
log.error("连接 RPC 失败: ", e);
|
||||
System.exit(-1);
|
||||
}
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
logger.info("关闭...");
|
||||
log.info("关闭...");
|
||||
diableRecvMsg();
|
||||
if (isLocalHostPort) {
|
||||
INSTANCE.WxDestroySDK();
|
||||
@ -102,7 +126,7 @@ public class Client {
|
||||
long size = cmdSocket.receive(ret, true);
|
||||
return Response.parseFrom(Arrays.copyOfRange(ret.array(), 0, (int)size));
|
||||
} catch (Exception e) {
|
||||
logger.error("命令调用失败: ", e);
|
||||
log.error("命令调用失败: ", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -110,7 +134,7 @@ public class Client {
|
||||
/**
|
||||
* 当前微信客户端是否登录微信号
|
||||
*
|
||||
* @return
|
||||
* @return 是否登录结果
|
||||
*/
|
||||
public boolean isLogin() {
|
||||
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_IS_LOGIN_VALUE).build();
|
||||
@ -124,22 +148,21 @@ public class Client {
|
||||
/**
|
||||
* 获得微信客户端登录的微信ID
|
||||
*
|
||||
* @return
|
||||
* @return 微信ID
|
||||
*/
|
||||
public String getSelfWxid() {
|
||||
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
|
||||
* @return 消息类型集合
|
||||
*/
|
||||
public Map<Integer, String> getMsgTypes() {
|
||||
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_GET_MSG_TYPES_VALUE).build();
|
||||
@ -147,7 +170,6 @@ public class Client {
|
||||
if (rsp != null) {
|
||||
return rsp.getTypes().getTypesMap();
|
||||
}
|
||||
|
||||
return Wcf.MsgTypes.newBuilder().build().getTypesMap();
|
||||
}
|
||||
|
||||
@ -159,7 +181,7 @@ public class Client {
|
||||
* "filehelper": "文件传输助手",
|
||||
* "newsapp": "新闻",
|
||||
*
|
||||
* @return
|
||||
* @return 联系人列表
|
||||
*/
|
||||
public List<RpcContact> getContacts() {
|
||||
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_GET_CONTACTS_VALUE).build();
|
||||
@ -167,7 +189,6 @@ public class Client {
|
||||
if (rsp != null) {
|
||||
return rsp.getContacts().getContactsList();
|
||||
}
|
||||
|
||||
return Wcf.RpcContacts.newBuilder().build().getContactsList();
|
||||
}
|
||||
|
||||
@ -176,7 +197,7 @@ public class Client {
|
||||
*
|
||||
* @param db 数据库名
|
||||
* @param sql 执行的sql语句
|
||||
* @return
|
||||
* @return 数据记录列表
|
||||
*/
|
||||
public List<DbRow> querySql(String db, String sql) {
|
||||
DbQuery dbQuery = DbQuery.newBuilder().setSql(sql).setDb(db).build();
|
||||
@ -191,7 +212,7 @@ public class Client {
|
||||
/**
|
||||
* 获取所有数据库名
|
||||
*
|
||||
* @return
|
||||
* @return 数据库名称列表
|
||||
*/
|
||||
public List<String> getDbNames() {
|
||||
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_GET_DB_NAMES_VALUE).build();
|
||||
@ -199,15 +220,14 @@ public class Client {
|
||||
if (rsp != null) {
|
||||
return rsp.getDbs().getNamesList();
|
||||
}
|
||||
|
||||
return Wcf.DbNames.newBuilder().build().getNamesList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定数据库中的所有表
|
||||
*
|
||||
* @param db
|
||||
* @return
|
||||
* @param db 数据库名称
|
||||
* @return 数据库中表列表
|
||||
*/
|
||||
public Map<String, String> getDbTables(String db) {
|
||||
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_GET_DB_TABLES_VALUE).setStr(db).build();
|
||||
@ -218,7 +238,6 @@ public class Client {
|
||||
tables.put(tbl.getName(), tbl.getSql());
|
||||
}
|
||||
}
|
||||
|
||||
return tables;
|
||||
}
|
||||
|
||||
@ -233,17 +252,16 @@ public class Client {
|
||||
* @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();
|
||||
logger.debug("sendText: {}", bytesToHex(req.toByteArray()));
|
||||
log.debug("sendText: {}", bytesToHex(req.toByteArray()));
|
||||
Response rsp = sendCmd(req);
|
||||
int ret = -1;
|
||||
if (rsp != null) {
|
||||
ret = rsp.getStatus();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -257,13 +275,12 @@ public class Client {
|
||||
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();
|
||||
logger.debug("sendImage: {}", bytesToHex(req.toByteArray()));
|
||||
log.debug("sendImage: {}", bytesToHex(req.toByteArray()));
|
||||
Response rsp = sendCmd(req);
|
||||
int ret = -1;
|
||||
if (rsp != null) {
|
||||
ret = rsp.getStatus();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -277,13 +294,12 @@ public class Client {
|
||||
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();
|
||||
logger.debug("sendFile: {}", bytesToHex(req.toByteArray()));
|
||||
log.debug("sendFile: {}", bytesToHex(req.toByteArray()));
|
||||
Response rsp = sendCmd(req);
|
||||
int ret = -1;
|
||||
if (rsp != null) {
|
||||
ret = rsp.getStatus();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -292,20 +308,19 @@ public class Client {
|
||||
*
|
||||
* @param receiver 接收者微信id
|
||||
* @param xml xml内容
|
||||
* @param path
|
||||
* @param type
|
||||
* @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();
|
||||
logger.debug("sendXml: {}", bytesToHex(req.toByteArray()));
|
||||
log.debug("sendXml: {}", bytesToHex(req.toByteArray()));
|
||||
Response rsp = sendCmd(req);
|
||||
int ret = -1;
|
||||
if (rsp != null) {
|
||||
ret = rsp.getStatus();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -319,13 +334,12 @@ public class Client {
|
||||
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();
|
||||
logger.debug("sendEmotion: {}", bytesToHex(req.toByteArray()));
|
||||
log.debug("sendEmotion: {}", bytesToHex(req.toByteArray()));
|
||||
Response rsp = sendCmd(req);
|
||||
int ret = -1;
|
||||
if (rsp != null) {
|
||||
ret = rsp.getStatus();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -413,12 +427,12 @@ public class Client {
|
||||
/**
|
||||
* 判断是否是艾特自己的消息
|
||||
*
|
||||
* @param wxMsgXml
|
||||
* @param wxMsgContent
|
||||
* @return
|
||||
* @param wxMsgXml XML消息
|
||||
* @param wxMsgContent 消息内容
|
||||
* @return 是否
|
||||
*/
|
||||
public boolean isAtMeMsg(String wxMsgXml, String wxMsgContent) {
|
||||
String format = String.format("<atuserlist><![CDATA[%s]]></atuserlist>", getSelfWxid());
|
||||
String format = String.format("<atuserlist><![CDATA[%s]]></atuserlist>", getSelfWxId());
|
||||
boolean isAtAll = wxMsgContent.startsWith("@所有人") || wxMsgContent.startsWith("@all");
|
||||
if (wxMsgXml.contains(format) && !isAtAll) {
|
||||
return true;
|
||||
@ -430,9 +444,10 @@ public class Client {
|
||||
try {
|
||||
msgSocket = new Pair1Socket();
|
||||
msgSocket.dial(url);
|
||||
msgSocket.setReceiveTimeout(2000); // 2 秒超时
|
||||
// 设置 2 秒超时
|
||||
msgSocket.setReceiveTimeout(2000);
|
||||
} catch (Exception e) {
|
||||
logger.error("创建消息 RPC 失败", e);
|
||||
log.error("创建消息 RPC 失败", e);
|
||||
return;
|
||||
}
|
||||
ByteBuffer bb = ByteBuffer.allocate(BUFFER_SIZE);
|
||||
@ -448,7 +463,7 @@ public class Client {
|
||||
try {
|
||||
msgSocket.close();
|
||||
} catch (Exception e) {
|
||||
logger.error("关闭连接失败", e);
|
||||
log.error("关闭连接失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -460,7 +475,7 @@ public class Client {
|
||||
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_ENABLE_RECV_TXT_VALUE).build();
|
||||
Response rsp = sendCmd(req);
|
||||
if (rsp == null) {
|
||||
logger.error("启动消息接收失败");
|
||||
log.error("启动消息接收失败");
|
||||
isReceivingMsg = false;
|
||||
return;
|
||||
}
|
||||
@ -501,21 +516,34 @@ public class Client {
|
||||
for (RpcContact c : contacts) {
|
||||
int value = c.getGender();
|
||||
String gender;
|
||||
if (value == 1) {
|
||||
if (SexEnum.BOY.getCode().equals(String.valueOf(value))) {
|
||||
gender = "男";
|
||||
} else if (value == 2) {
|
||||
} else if (SexEnum.GIRL.getCode().equals(String.valueOf(value))) {
|
||||
gender = "女";
|
||||
} else {
|
||||
gender = "未知";
|
||||
}
|
||||
|
||||
logger.info("{}, {}, {}, {}, {}, {}, {}", c.getWxid(), c.getName(), c.getCode(), c.getCountry(), c.getProvince(), c.getCity(), gender);
|
||||
log.info("{}, {}, {}, {}, {}, {}, {}", c.getWxid(), c.getName(), c.getCode(), c.getCountry(), c.getProvince(), c.getCity(), gender);
|
||||
}
|
||||
}
|
||||
|
||||
public void printWxMsg(WxMsg msg) {
|
||||
logger.info("{}[{}]:{}:{}:{}\n{}", msg.getSender(), msg.getRoomid(), msg.getId(), msg.getType(),
|
||||
msg.getXml().replace("\n", "").replace("\t", ""), msg.getContent());
|
||||
WxMsgDTO dto = new WxMsgDTO();
|
||||
dto.setIsSelf(msg.getIsSelf());
|
||||
dto.setIsGroup(msg.getIsGroup());
|
||||
dto.setId(msg.getId());
|
||||
dto.setType(msg.getType());
|
||||
dto.setTs(msg.getTs());
|
||||
dto.setRoomId(msg.getRoomid());
|
||||
dto.setContent(msg.getContent());
|
||||
dto.setSender(msg.getSender());
|
||||
dto.setSign(msg.getSign());
|
||||
dto.setThumb(msg.getThumb());
|
||||
dto.setExtra(msg.getExtra());
|
||||
dto.setXml(msg.getXml().replace("\n", "").replace("\t", ""));
|
||||
|
||||
String jsonString = JSONObject.toJSONString(dto);
|
||||
log.info("收到消息: {}", jsonString);
|
||||
}
|
||||
|
||||
private String bytesToHex(byte[] bytes) {
|
||||
@ -532,4 +560,30 @@ public class Client {
|
||||
}
|
||||
}
|
||||
|
||||
public void forwardMsg(WxMsg msg, String url) {
|
||||
WxMsgDTO dto = new WxMsgDTO();
|
||||
dto.setIsSelf(msg.getIsSelf());
|
||||
dto.setIsGroup(msg.getIsGroup());
|
||||
dto.setId(msg.getId());
|
||||
dto.setType(msg.getType());
|
||||
dto.setTs(msg.getTs());
|
||||
dto.setRoomId(msg.getRoomid());
|
||||
dto.setContent(msg.getContent());
|
||||
dto.setSender(msg.getSender());
|
||||
dto.setSign(msg.getSign());
|
||||
dto.setThumb(msg.getThumb());
|
||||
dto.setExtra(msg.getExtra());
|
||||
dto.setXml(msg.getXml().replace("\n", "").replace("\t", ""));
|
||||
|
||||
String jsonString = JSONObject.toJSONString(dto);
|
||||
try {
|
||||
String responseStr = HttpClientUtil.doPostJson(url, jsonString);
|
||||
if (!JSONObject.parseObject(responseStr).getString("code").equals("200")) {
|
||||
log.error("本机消息转发失败!-URL:{}", url);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("转发接口报错:", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,29 +1,28 @@
|
||||
package com.iamteer.service;
|
||||
package com.wechat.ferry.service;
|
||||
|
||||
import com.sun.jna.Library;
|
||||
|
||||
/**
|
||||
* SDK.dll的接口类
|
||||
*
|
||||
* @Description
|
||||
* @Author xinggq
|
||||
* @Date 2024/7/10
|
||||
* @author xinggq
|
||||
* @date 2024-07-10 15:21
|
||||
*/
|
||||
public interface SDK extends Library {
|
||||
|
||||
/**
|
||||
* 初始化SDK
|
||||
*
|
||||
* @param debug
|
||||
* @param port
|
||||
* @return
|
||||
* @param debug 开发模式
|
||||
* @param port 端口
|
||||
* @return 状态值
|
||||
*/
|
||||
int WxInitSDK(boolean debug, int port);
|
||||
|
||||
/**
|
||||
* 退出SDK
|
||||
*
|
||||
* @return
|
||||
* @return 状态值
|
||||
*/
|
||||
int WxDestroySDK();
|
||||
|
11
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/service/WeChatDllService.java
vendored
Normal file
11
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/service/WeChatDllService.java
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
package com.wechat.ferry.service;
|
||||
|
||||
/**
|
||||
* 业务接口-对接原本DLL的接口
|
||||
*
|
||||
* @author chandler
|
||||
* @date 2024-10-01 15:57
|
||||
*/
|
||||
public interface WeChatDllService {
|
||||
|
||||
}
|
21
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/service/WeChatMsgService.java
vendored
Normal file
21
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/service/WeChatMsgService.java
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
package com.wechat.ferry.service;
|
||||
|
||||
/**
|
||||
* 业务接口-消息处理
|
||||
*
|
||||
* @author chandler
|
||||
* @date 2024-10-01 14:30
|
||||
*/
|
||||
public interface WeChatMsgService {
|
||||
|
||||
/**
|
||||
* 接收消息
|
||||
*
|
||||
* @param jsonString json数据
|
||||
*
|
||||
* @author chandler
|
||||
* @date 2024-10-01 14:33
|
||||
*/
|
||||
void receiveMsg(String jsonString);
|
||||
|
||||
}
|
3
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/service/impl/.gitkeep
vendored
Normal file
3
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/service/impl/.gitkeep
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file !.gitkeep
|
@ -0,0 +1,19 @@
|
||||
package com.wechat.ferry.service.impl;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.wechat.ferry.service.WeChatDllService;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 业务实现层-对接原本DLL的接口
|
||||
*
|
||||
* @author chandler
|
||||
* @date 2024-10-01 15:58
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class WeChatDllServiceImpl implements WeChatDllService {
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.wechat.ferry.service.impl;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.wechat.ferry.entity.dto.WxMsgDTO;
|
||||
import com.wechat.ferry.service.WeChatMsgService;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 业务实现层-消息处理
|
||||
*
|
||||
* @author chandler
|
||||
* @date 2024-10-01 14:35
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class WeChatMsgServiceImpl implements WeChatMsgService {
|
||||
|
||||
@Override
|
||||
public void receiveMsg(String jsonString) {
|
||||
// 转为JSON对象
|
||||
WxMsgDTO dto = JSON.parseObject(jsonString, WxMsgDTO.class);
|
||||
// TODO 这里可以拓展自己需要的功能
|
||||
log.debug("[收到消息]-[消息内容]-打印:{}", dto);
|
||||
}
|
||||
|
||||
}
|
169
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/utils/HttpClientUtil.java
vendored
Normal file
169
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/utils/HttpClientUtil.java
vendored
Normal file
@ -0,0 +1,169 @@
|
||||
package com.wechat.ferry.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* HTTP请求类
|
||||
*/
|
||||
@Slf4j
|
||||
@SuppressWarnings("all")
|
||||
public class HttpClientUtil {
|
||||
|
||||
/**
|
||||
* 带参数的get请求
|
||||
*
|
||||
* @param url
|
||||
* @param param
|
||||
* @return String
|
||||
*/
|
||||
public static String doGet(String url, Map<String, String> param) {
|
||||
// 创建Httpclient对象
|
||||
CloseableHttpClient httpclient = HttpClients.createDefault();
|
||||
|
||||
String resultString = "";
|
||||
CloseableHttpResponse response = null;
|
||||
try {
|
||||
// 创建uri
|
||||
URIBuilder builder = new URIBuilder(url);
|
||||
if (param != null) {
|
||||
for (String key : param.keySet()) {
|
||||
builder.addParameter(key, param.get(key));
|
||||
}
|
||||
}
|
||||
URI uri = builder.build();
|
||||
// 创建http GET请求
|
||||
HttpGet httpGet = new HttpGet(uri);
|
||||
// 执行请求
|
||||
response = httpclient.execute(httpGet);
|
||||
// 判断返回状态是否为200
|
||||
if (response.getStatusLine().getStatusCode() == 200) {
|
||||
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
httpclient.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return resultString;
|
||||
}
|
||||
|
||||
/**
|
||||
* 不带参数的get请求
|
||||
*
|
||||
* @param url
|
||||
* @return String
|
||||
*/
|
||||
public static String doGet(String url) {
|
||||
return doGet(url, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 带参数的post请求
|
||||
*
|
||||
* @param url
|
||||
* @param param
|
||||
* @return String
|
||||
*/
|
||||
public static String doPost(String url, Map<String, String> param) {
|
||||
// 创建Httpclient对象
|
||||
CloseableHttpClient httpClient = HttpClients.createDefault();
|
||||
CloseableHttpResponse response = null;
|
||||
String resultString = "";
|
||||
try {
|
||||
// 创建Http Post请求
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
// 创建参数列表
|
||||
if (param != null) {
|
||||
List<NameValuePair> paramList = new ArrayList<>();
|
||||
for (String key : param.keySet()) {
|
||||
paramList.add(new BasicNameValuePair(key, param.get(key)));
|
||||
}
|
||||
// 模拟表单
|
||||
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
|
||||
httpPost.setEntity(entity);
|
||||
}
|
||||
// 执行http请求
|
||||
response = httpClient.execute(httpPost);
|
||||
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
response.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return resultString;
|
||||
}
|
||||
|
||||
/**
|
||||
* 不带参数的post请求
|
||||
*
|
||||
* @param url
|
||||
* @return String
|
||||
*/
|
||||
public static String doPost(String url) {
|
||||
return doPost(url, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 传送json类型的post请求
|
||||
*
|
||||
* @param url
|
||||
* @param json
|
||||
* @return String
|
||||
*/
|
||||
public static String doPostJson(String url, String json) {
|
||||
// 创建Httpclient对象
|
||||
CloseableHttpClient httpClient = HttpClients.createDefault();
|
||||
CloseableHttpResponse response = null;
|
||||
String resultString = "";
|
||||
try {
|
||||
// 创建Http Post请求
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
// 创建请求内容
|
||||
StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
|
||||
httpPost.setEntity(entity);
|
||||
// 执行http请求
|
||||
response = httpClient.execute(httpPost);
|
||||
resultString = EntityUtils.toString(response.getEntity(), "utf-8");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
response.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return resultString;
|
||||
}
|
||||
|
||||
}
|
130
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/utils/XmlJsonConvertUtil.java
vendored
Normal file
130
clients/java/wechat-ferry-mvn/src/main/java/com/wechat/ferry/utils/XmlJsonConvertUtil.java
vendored
Normal file
@ -0,0 +1,130 @@
|
||||
package com.wechat.ferry.utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.List;
|
||||
|
||||
import org.dom4j.Attribute;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.DocumentHelper;
|
||||
import org.dom4j.Element;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class XmlJsonConvertUtil {
|
||||
|
||||
public static String readFile(String path) {
|
||||
String str = "";
|
||||
try {
|
||||
File file = new File(path);
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
FileChannel fc = fis.getChannel();
|
||||
ByteBuffer bb = ByteBuffer.allocate(new Long(file.length()).intValue());
|
||||
// fc向buffer中读入数据
|
||||
fc.read(bb);
|
||||
bb.flip();
|
||||
str = new String(bb.array(), "UTF8");
|
||||
fc.close();
|
||||
fis.close();
|
||||
} catch (Exception e) {
|
||||
log.error("异常:{} ", e.getMessage());
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* xml转json
|
||||
*
|
||||
* @param xmlStr
|
||||
* @return
|
||||
*/
|
||||
public static JSONObject xml2Json(String xmlStr) {
|
||||
JSONObject json = new JSONObject();
|
||||
try {
|
||||
xmlStr = xmlStr.replace("<?xml version=\\\"1.0\\\"?>\\n", "");
|
||||
Document doc = DocumentHelper.parseText(xmlStr);
|
||||
dom4j2Json(doc.getRootElement(), json);
|
||||
} catch (DocumentException e) {
|
||||
log.error("异常:{} ", e.getMessage());
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
/**
|
||||
* xml转json
|
||||
*
|
||||
* @param element
|
||||
* @param json
|
||||
*/
|
||||
public static void dom4j2Json(Element element, JSONObject json) {
|
||||
// 如果是属性
|
||||
for (Object o : element.attributes()) {
|
||||
Attribute attr = (Attribute)o;
|
||||
if (!isEmpty(attr.getValue())) {
|
||||
json.put("@" + attr.getName(), attr.getValue());
|
||||
}
|
||||
}
|
||||
List<Element> chdEl = element.elements();
|
||||
if (chdEl.isEmpty() && !isEmpty(element.getText())) {
|
||||
// 如果没有子元素,只有一个值
|
||||
json.put(element.getName(), element.getText());
|
||||
}
|
||||
|
||||
for (Element e : chdEl) {
|
||||
// 有子元素
|
||||
if (!e.elements().isEmpty()) {
|
||||
// 子元素也有子元素
|
||||
JSONObject chdjson = new JSONObject();
|
||||
dom4j2Json(e, chdjson);
|
||||
Object o = json.get(e.getName());
|
||||
if (o != null) {
|
||||
JSONArray jsona = null;
|
||||
if (o instanceof JSONObject) {
|
||||
// 如果此元素已存在,则转为jsonArray
|
||||
JSONObject jsono = (JSONObject)o;
|
||||
json.remove(e.getName());
|
||||
jsona = new JSONArray();
|
||||
jsona.add(jsono);
|
||||
jsona.add(chdjson);
|
||||
}
|
||||
if (o instanceof JSONArray) {
|
||||
jsona = (JSONArray)o;
|
||||
jsona.add(chdjson);
|
||||
}
|
||||
json.put(e.getName(), jsona);
|
||||
} else {
|
||||
if (!chdjson.isEmpty()) {
|
||||
json.put(e.getName(), chdjson);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// 子元素没有子元素
|
||||
for (Object o : element.attributes()) {
|
||||
Attribute attr = (Attribute)o;
|
||||
if (!isEmpty(attr.getValue())) {
|
||||
json.put("@" + attr.getName(), attr.getValue());
|
||||
}
|
||||
}
|
||||
if (!e.getText().isEmpty()) {
|
||||
json.put(e.getName(), e.getText());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isEmpty(String str) {
|
||||
if (str == null || str.trim().isEmpty() || "null".equals(str)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -9,15 +9,16 @@ spring:
|
||||
# 配置应用信息
|
||||
application:
|
||||
# 应用名
|
||||
name: wcferry-mvn
|
||||
name: wechat-ferry
|
||||
# swagger适配
|
||||
mvc:
|
||||
pathmatch:
|
||||
matching-strategy: ant_path_matcher
|
||||
|
||||
# 本服务参数
|
||||
wcferry:
|
||||
# DLL文件位置
|
||||
dll-path: E:\WeChatFerry\clients\java\wcferry-mvn\dll\sdk.dll
|
||||
# socket端口
|
||||
socket-port: 10086
|
||||
wechat:
|
||||
ferry:
|
||||
# DLL文件位置
|
||||
dll-path: E:\WeChatFerry\clients\java\wechat-ferry-mvn\dll\sdk.dll
|
||||
# socket端口
|
||||
socket-port: 10086
|
@ -83,6 +83,13 @@
|
||||
<logger name="org.springframework.boot.autoconfigure.logging" level="INFO">
|
||||
<appender-ref ref="console"/>
|
||||
</logger>
|
||||
<!-- httpclient 屏蔽 -->
|
||||
<logger name="org.apache" level="OFF">
|
||||
<appender-ref ref="error"/>
|
||||
</logger>
|
||||
<logger name="httpclient" level="OFF">
|
||||
<appender-ref ref="error"/>
|
||||
</logger>
|
||||
|
||||
<!-- Level: FATAL 0 ERROR 3 WARN 4 INFO 6 DEBUG 7 -->
|
||||
<root level="DEBUG">
|
3
clients/java/wechat-ferry-mvn/src/main/resources/proto/.gitkeep
vendored
Normal file
3
clients/java/wechat-ferry-mvn/src/main/resources/proto/.gitkeep
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file !.gitkeep
|
@ -1,7 +1,7 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package wcf;
|
||||
option java_package = "com.iamteer.entity";
|
||||
option java_package = "com.wechat.ferry.entity.po";
|
||||
|
||||
enum Functions {
|
||||
FUNC_RESERVED = 0x00;
|
3
clients/java/wechat-ferry-mvn/src/main/resources/win32-x86-64/.gitkeep
vendored
Normal file
3
clients/java/wechat-ferry-mvn/src/main/resources/win32-x86-64/.gitkeep
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file !.gitkeep
|
Loading…
Reference in New Issue
Block a user