feat(0): [java]-[wechat-ferry-mvn]-消息接口支持boot接口打印,便于后续boot项目自身接管处理

This commit is contained in:
chandler 2024-10-01 15:47:25 +08:00
parent ca6a8e9602
commit 478a10008e
10 changed files with 418 additions and 59 deletions

View File

@ -59,6 +59,12 @@
<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>

View File

@ -2,6 +2,7 @@ package com.wechat.ferry.config;
import javax.annotation.Resource;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -22,6 +23,9 @@ public class WeChatConfiguration {
@Resource
private WeChatFerryProperties properties;
@Resource
private ServerProperties serverProperties;
@Bean
public WeChatSocketClient client() {
log.debug("[读取配置文件]-端口:{},地址:{}", properties.getSocketPort(), properties.getDllPath());
@ -29,8 +33,6 @@ public class WeChatConfiguration {
// Client client = new Client("127.0.0.1", 10086);
// 本地启动 RPC
// Client client = new Client(); // 默认 10086 端口
// Client client = new Client(10088,true); // 也可以指定端口
WeChatSocketClient wechatSocketClient = new WeChatSocketClient(properties.getSocketPort(), properties.getDllPath());
// 是否已登录
@ -69,12 +71,17 @@ public class WeChatConfiguration {
// 发送表情消息gif 必须要存在
// client.sendEmotion("C:\\Projs\\WeChatFerry\\emo.gif", "filehelper");
// 使用本机打印
String url = "http://localhost:" + serverProperties.getPort() + "/wechat/msg/receive";
// 接收消息并调用 printWxMsg 处理
wechatSocketClient.enableRecvMsg(100);
Thread thread = new Thread(new Runnable() {
public void run() {
while (wechatSocketClient.getIsReceivingMsg()) {
wechatSocketClient.printWxMsg(wechatSocketClient.getMsg());
// 只打印
// wechatSocketClient.printWxMsg(wechatSocketClient.getMsg());
// 转发到boot项目进行消息处理
wechatSocketClient.forwardMsg(wechatSocketClient.getMsg(), url);
}
}
});

View 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.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 JSONObject jsonData) {
log.debug("jsonData:{}", jsonData);
return TResponse.ok(ResponseCodeEnum.SUCCESS);
}
}

View 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;
}

View File

@ -24,7 +24,9 @@ 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.entity.vo.response.WxMsgResp;
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;
@ -39,33 +41,49 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
public class WeChatSocketClient {
private static final int BUFFER_SIZE = 16 * 1024 * 1024; // 16M
/**
* 消息缓冲区大小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 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 WeChatSocketClient() {
this(DEFAULT_HOST, PORT, false, DEFAULT_DLL_PATH);
}
public WeChatSocketClient(int port, String dllPath) {
public WeChatSocketClient(Integer port, String dllPath) {
this(DEFAULT_HOST, port, false, dllPath);
}
public WeChatSocketClient(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);
@ -73,7 +91,7 @@ public class WeChatSocketClient {
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;
}
@ -83,7 +101,6 @@ public class WeChatSocketClient {
try {
cmdSocket = new Pair1Socket();
cmdSocket.dial(url);
// logger.info("请点击登录微信");
while (!isLogin()) {
// 直到登录成功
waitMs(1000);
@ -117,7 +134,7 @@ public class WeChatSocketClient {
/**
* 当前微信客户端是否登录微信号
*
* @return
* @return 是否登录结果
*/
public boolean isLogin() {
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_IS_LOGIN_VALUE).build();
@ -131,22 +148,21 @@ public class WeChatSocketClient {
/**
* 获得微信客户端登录的微信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();
@ -154,7 +170,6 @@ public class WeChatSocketClient {
if (rsp != null) {
return rsp.getTypes().getTypesMap();
}
return Wcf.MsgTypes.newBuilder().build().getTypesMap();
}
@ -166,7 +181,7 @@ public class WeChatSocketClient {
* "filehelper": "文件传输助手",
* "newsapp": "新闻",
*
* @return
* @return 联系人列表
*/
public List<RpcContact> getContacts() {
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_GET_CONTACTS_VALUE).build();
@ -174,7 +189,6 @@ public class WeChatSocketClient {
if (rsp != null) {
return rsp.getContacts().getContactsList();
}
return Wcf.RpcContacts.newBuilder().build().getContactsList();
}
@ -183,7 +197,7 @@ public class WeChatSocketClient {
*
* @param db 数据库名
* @param sql 执行的sql语句
* @return
* @return 数据记录列表
*/
public List<DbRow> querySql(String db, String sql) {
DbQuery dbQuery = DbQuery.newBuilder().setSql(sql).setDb(db).build();
@ -198,7 +212,7 @@ public class WeChatSocketClient {
/**
* 获取所有数据库名
*
* @return
* @return 数据库名称列表
*/
public List<String> getDbNames() {
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_GET_DB_NAMES_VALUE).build();
@ -206,15 +220,14 @@ public class WeChatSocketClient {
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();
@ -225,7 +238,6 @@ public class WeChatSocketClient {
tables.put(tbl.getName(), tbl.getSql());
}
}
return tables;
}
@ -240,7 +252,7 @@ public class WeChatSocketClient {
* @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();
@ -250,7 +262,6 @@ public class WeChatSocketClient {
if (rsp != null) {
ret = rsp.getStatus();
}
return ret;
}
@ -270,7 +281,6 @@ public class WeChatSocketClient {
if (rsp != null) {
ret = rsp.getStatus();
}
return ret;
}
@ -290,7 +300,6 @@ public class WeChatSocketClient {
if (rsp != null) {
ret = rsp.getStatus();
}
return ret;
}
@ -299,8 +308,8 @@ public class WeChatSocketClient {
*
* @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) {
@ -312,7 +321,6 @@ public class WeChatSocketClient {
if (rsp != null) {
ret = rsp.getStatus();
}
return ret;
}
@ -332,7 +340,6 @@ public class WeChatSocketClient {
if (rsp != null) {
ret = rsp.getStatus();
}
return ret;
}
@ -420,12 +427,12 @@ public class WeChatSocketClient {
/**
* 判断是否是艾特自己的消息
*
* @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;
@ -437,7 +444,8 @@ public class WeChatSocketClient {
try {
msgSocket = new Pair1Socket();
msgSocket.dial(url);
msgSocket.setReceiveTimeout(2000); // 2 秒超时
// 设置 2 秒超时
msgSocket.setReceiveTimeout(2000);
} catch (Exception e) {
log.error("创建消息 RPC 失败", e);
return;
@ -508,14 +516,13 @@ public class WeChatSocketClient {
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 = "未知";
}
log.info("{}, {}, {}, {}, {}, {}, {}", c.getWxid(), c.getName(), c.getCode(), c.getCountry(), c.getProvince(), c.getCity(), gender);
}
}
@ -553,4 +560,30 @@ public class WeChatSocketClient {
}
}
public void forwardMsg(WxMsg msg, String url) {
WxMsgResp wxMsgResp = new WxMsgResp();
wxMsgResp.setIsSelf(msg.getIsSelf());
wxMsgResp.setIsGroup(msg.getIsGroup());
wxMsgResp.setId(msg.getId());
wxMsgResp.setType(msg.getType());
wxMsgResp.setTs(msg.getTs());
wxMsgResp.setRoomId(msg.getRoomid());
wxMsgResp.setContent(msg.getContent());
wxMsgResp.setSender(msg.getSender());
wxMsgResp.setSign(msg.getSign());
wxMsgResp.setThumb(msg.getThumb());
wxMsgResp.setExtra(msg.getExtra());
wxMsgResp.setXml(msg.getXml().replace("\n", "").replace("\t", ""));
String jsonString = JSONObject.toJSONString(wxMsgResp);
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);
}
}
}

View File

@ -5,9 +5,6 @@ import com.sun.jna.Library;
/**
* SDK.dll的接口类
*
* @Author xinggq
* @Date 2024/7/10
*
* @author xinggq
* @date 2024-07-10 15:21
*/
@ -15,17 +12,17 @@ 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();

View 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);
}

View File

@ -0,0 +1,33 @@
package com.wechat.ferry.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.wechat.ferry.handle.WeChatSocketClient;
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 {
private WeChatSocketClient wechatSocketClient;
@Autowired
public void setWechatSocketClient(WeChatSocketClient wechatSocketClient) {
this.wechatSocketClient = wechatSocketClient;
}
@Override
public void receiveMsg(String jsonString) {
log.debug("[收到消息]-[消息内容]-打印:{}", jsonString);
}
}

View 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;
}
}

View File

@ -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">