Refactoring
This commit is contained in:
@@ -0,0 +1,564 @@
|
||||
package com.iamteer;
|
||||
|
||||
import com.iamteer.Wcf.*;
|
||||
import io.sisu.nng.Socket;
|
||||
import io.sisu.nng.pair.Pair1Socket;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.URL;
|
||||
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;
|
||||
|
||||
public class Client {
|
||||
private static final Logger logger = LoggerFactory.getLogger(Client.class);
|
||||
private final int BUFFER_SIZE = 16 * 1024 * 1024; // 16M
|
||||
private Socket cmdSocket = null;
|
||||
private Socket msgSocket = null;
|
||||
private String host = "127.0.0.1";
|
||||
private int port = 10086;
|
||||
private boolean isReceivingMsg = false;
|
||||
private boolean isLocalHostPort = false;
|
||||
private BlockingQueue<WxMsg> msgQ;
|
||||
private String wcfPath;
|
||||
|
||||
public Client(String host, int port) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
String cmdUrl = "tcp://" + host + ":" + port;
|
||||
connectRPC(cmdUrl);
|
||||
}
|
||||
|
||||
public Client(int port, boolean debug) {
|
||||
initClient(this.host, port, debug);
|
||||
}
|
||||
|
||||
public Client(boolean debug) {
|
||||
initClient(this.host, this.port, debug);
|
||||
}
|
||||
|
||||
private void initClient(String host, int port, boolean debug) {
|
||||
try {
|
||||
URL url = this.getClass().getResource("/win32-x86-64/wcf.exe");
|
||||
wcfPath = url.getFile();
|
||||
String[] cmd = new String[4];
|
||||
cmd[0] = wcfPath;
|
||||
cmd[1] = "start";
|
||||
cmd[2] = Integer.toString(port);
|
||||
if (debug) {
|
||||
cmd[3] = "debug";
|
||||
} else {
|
||||
cmd[3] = "";
|
||||
}
|
||||
int status = Runtime.getRuntime().exec(cmd).waitFor();
|
||||
if (status != 0) {
|
||||
logger.error("启动 RPC 失败: {}", status);
|
||||
System.exit(-1);
|
||||
}
|
||||
isLocalHostPort = true;
|
||||
String cmdUrl = "tcp://" + host + ":" + port;
|
||||
connectRPC(cmdUrl);
|
||||
} catch (Exception e) {
|
||||
logger.error("初始化失败: {}", e);
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
private void connectRPC(String url) {
|
||||
try {
|
||||
cmdSocket = new Pair1Socket();
|
||||
cmdSocket.dial(url);
|
||||
logger.info("请点击登录微信");
|
||||
while (!isLogin()) { // 直到登录成功
|
||||
waitMs(1000);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("连接 RPC 失败: ", e);
|
||||
System.exit(-1);
|
||||
}
|
||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||
public void run() {
|
||||
logger.info("关闭...");
|
||||
diableRecvMsg();
|
||||
if (isLocalHostPort) {
|
||||
try {
|
||||
String[] cmd = new String[2];
|
||||
cmd[0] = wcfPath;
|
||||
cmd[1] = "stop";
|
||||
Process process = Runtime.getRuntime().exec(cmd);
|
||||
int status = process.waitFor();
|
||||
if (status != 0) {
|
||||
System.err.println("停止机器人失败: " + status);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Response sendCmd(Request req) {
|
||||
try {
|
||||
ByteBuffer bb = ByteBuffer.wrap(req.toByteArray());
|
||||
cmdSocket.send(bb);
|
||||
ByteBuffer ret = ByteBuffer.allocate(BUFFER_SIZE);
|
||||
long size = cmdSocket.receive(ret, true);
|
||||
return Response.parseFrom(Arrays.copyOfRange(ret.array(), 0, (int) size));
|
||||
} catch (Exception e) {
|
||||
logger.error("命令调用失败: ", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前微信客户端是否登录微信号
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isLogin() {
|
||||
Request req = new Request.Builder().setFuncValue(Functions.FUNC_IS_LOGIN_VALUE).build();
|
||||
Response rsp = sendCmd(req);
|
||||
if (rsp != null) {
|
||||
return rsp.getStatus() == 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得微信客户端登录的微信ID
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getSelfWxid() {
|
||||
Request req = new Request.Builder().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 = new Request.Builder().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 = new Request.Builder().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执行结果
|
||||
*
|
||||
* @param db 数据库名
|
||||
* @param sql 执行的sql语句
|
||||
* @return
|
||||
*/
|
||||
public List<DbRow> querySql(String db, String sql) {
|
||||
DbQuery dbQuery = DbQuery.newBuilder().setSql(sql).setDb(db).build();
|
||||
Request req = new Request.Builder().setFuncValue(Functions.FUNC_EXEC_DB_QUERY_VALUE).setQuery(dbQuery).build();
|
||||
Response rsp = sendCmd(req);
|
||||
if (rsp != null) {
|
||||
return rsp.getRows().getRowsList();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有数据库名
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<String> getDbNames() {
|
||||
Request req = new Request.Builder().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 = new Request.Builder().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: 消息接收人,私聊为 wxid(wxid_xxxxxxxxxxxxxx),群聊为
|
||||
* roomid(xxxxxxxxxx@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 = new Request.Builder().setFuncValue(Functions.FUNC_SEND_TXT_VALUE).setTxt(textMsg).build();
|
||||
logger.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 = new Request.Builder().setFuncValue(Functions.FUNC_SEND_IMG_VALUE).setFile(pathMsg).build();
|
||||
logger.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 = new Request.Builder().setFuncValue(Functions.FUNC_SEND_FILE_VALUE).setFile(pathMsg).build();
|
||||
logger.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 = new Request.Builder().setFuncValue(Functions.FUNC_SEND_XML_VALUE).setXml(xmlMsg).build();
|
||||
logger.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 发送结果状态码
|
||||
*/
|
||||
public int sendEmotion(String path, String receiver) {
|
||||
Wcf.PathMsg pathMsg = Wcf.PathMsg.newBuilder().setPath(path).setReceiver(receiver).build();
|
||||
Request req = new Request.Builder().setFuncValue(Functions.FUNC_SEND_EMOTION_VALUE).setFile(pathMsg).build();
|
||||
logger.debug("sendEmotion: {}", bytesToHex(req.toByteArray()));
|
||||
Response rsp = sendCmd(req);
|
||||
int ret = -1;
|
||||
if (rsp != null) {
|
||||
ret = rsp.getStatus();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 接收好友请求
|
||||
*
|
||||
* @param v3 xml.attrib["encryptusername"]
|
||||
* @param v4 xml.attrib["ticket"]
|
||||
* @return 结果状态码
|
||||
*/
|
||||
public int acceptNewFriend(String v3, String v4) {
|
||||
int ret = -1;
|
||||
Verification verification = Verification.newBuilder().setV3(v3).setV4(v4).build();
|
||||
Request req = new Request.Builder().setFuncValue(Functions.FUNC_ACCEPT_FRIEND_VALUE).setV(verification).build();
|
||||
Response rsp = sendCmd(req);
|
||||
if (rsp != null) {
|
||||
ret = rsp.getStatus();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加群成员为微信好友
|
||||
*
|
||||
* @param roomID 群ID
|
||||
* @param wxIds 要加群的人列表,逗号分隔
|
||||
* @return 1 为成功,其他失败
|
||||
*/
|
||||
public int addChatroomMembers(String roomID, String wxIds) {
|
||||
int ret = -1;
|
||||
AddMembers addMembers = AddMembers.newBuilder().setRoomid(roomID).setWxids(wxIds).build();
|
||||
Request req = new Request.Builder().setFuncValue(Functions.FUNC_ADD_ROOM_MEMBERS_VALUE).setM(addMembers).build();
|
||||
Response rsp = sendCmd(req);
|
||||
if (rsp != null) {
|
||||
ret = rsp.getStatus();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 接收转账
|
||||
*
|
||||
* @param transferid 转账消息里的 transferid
|
||||
* @param wxId 转账消息里的发送人
|
||||
* @return 1 为成功,其他失败
|
||||
*/
|
||||
public int receiveTransfer(String transferid, String wxId) {
|
||||
int ret = -1;
|
||||
Transfer build = Transfer.newBuilder().setTid(transferid).setWxid(wxId).build();
|
||||
Request req = new Request.Builder().setFuncValue(Functions.FUNC_RECV_TRANSFER_VALUE).setTf(build).build();
|
||||
Response rsp = sendCmd(req);
|
||||
if (rsp != null) {
|
||||
ret = rsp.getStatus();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密图片
|
||||
*
|
||||
* @param srcPath 加密的图片路径
|
||||
* @param dstPath 解密的图片路径
|
||||
* @return 是否成功
|
||||
*/
|
||||
public boolean decryptImage(String srcPath, String dstPath) {
|
||||
int ret = -1;
|
||||
DecPath build = DecPath.newBuilder().setSrc(srcPath).setDst(dstPath).build();
|
||||
Request req = new Request.Builder().setFuncValue(Functions.FUNC_DECRYPT_IMAGE_VALUE).setDec(build).build();
|
||||
Response rsp = sendCmd(req);
|
||||
if (rsp != null) {
|
||||
ret = rsp.getStatus();
|
||||
}
|
||||
return ret == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取个人信息
|
||||
*
|
||||
* @return 个人信息
|
||||
*/
|
||||
public UserInfo getUserInfo() {
|
||||
Request req = new Request.Builder().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;
|
||||
}
|
||||
|
||||
public WxMsg getMsg() {
|
||||
try {
|
||||
return msgQ.take();
|
||||
} catch (Exception e) {
|
||||
// TODO: handle exception
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是艾特自己的消息
|
||||
*
|
||||
* @param wxMsgXml
|
||||
* @param wxMsgContent
|
||||
* @return
|
||||
*/
|
||||
public boolean isAtMeMsg(String wxMsgXml, String wxMsgContent) {
|
||||
String format = String.format("<atuserlist><![CDATA[%s]]></atuserlist>", getSelfWxid());
|
||||
boolean isAtAll = wxMsgContent.startsWith("@所有人") || wxMsgContent.startsWith("@all");
|
||||
if (wxMsgXml.contains(format) && !isAtAll) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void listenMsg(String url) {
|
||||
try {
|
||||
msgSocket = new Pair1Socket();
|
||||
msgSocket.dial(url);
|
||||
msgSocket.setReceiveTimeout(2000); // 2 秒超时
|
||||
} catch (Exception e) {
|
||||
logger.error("创建消息 RPC 失败: {}", e);
|
||||
return;
|
||||
}
|
||||
ByteBuffer bb = ByteBuffer.allocate(BUFFER_SIZE);
|
||||
while (isReceivingMsg) {
|
||||
try {
|
||||
long size = msgSocket.receive(bb, true);
|
||||
WxMsg wxMsg = Response.parseFrom(Arrays.copyOfRange(bb.array(), 0, (int) size)).getWxmsg();
|
||||
msgQ.put(wxMsg);
|
||||
} catch (Exception e) {
|
||||
// 多半是超时,忽略吧
|
||||
}
|
||||
}
|
||||
try {
|
||||
msgSocket.close();
|
||||
} catch (Exception e) {
|
||||
logger.error("关闭连接失败: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void enableRecvMsg(int qSize) {
|
||||
if (isReceivingMsg) {
|
||||
return;
|
||||
}
|
||||
|
||||
Request req = new Request.Builder().setFuncValue(Functions.FUNC_ENABLE_RECV_TXT_VALUE).build();
|
||||
Response rsp = sendCmd(req);
|
||||
if (rsp == null) {
|
||||
logger.error("启动消息接收失败");
|
||||
isReceivingMsg = false;
|
||||
return;
|
||||
}
|
||||
|
||||
isReceivingMsg = true;
|
||||
msgQ = new ArrayBlockingQueue<WxMsg>(qSize);
|
||||
String msgUrl = "tcp://" + this.host + ":" + (this.port + 1);
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
listenMsg(msgUrl);
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public int diableRecvMsg() {
|
||||
if (!isReceivingMsg) {
|
||||
return 1;
|
||||
}
|
||||
int ret = -1;
|
||||
Request req = new Request.Builder().setFuncValue(Functions.FUNC_DISABLE_RECV_TXT_VALUE).build();
|
||||
Response rsp = sendCmd(req);
|
||||
if (rsp != null) {
|
||||
ret = rsp.getStatus();
|
||||
if (ret == 0) {
|
||||
isReceivingMsg = false;
|
||||
}
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void waitMs(int ms) {
|
||||
try {
|
||||
Thread.sleep(ms);
|
||||
} catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
public void printContacts(List<RpcContact> contacts) {
|
||||
for (RpcContact c : contacts) {
|
||||
int value = c.getGender();
|
||||
String gender;
|
||||
if (value == 1) {
|
||||
gender = "男";
|
||||
} else if (value == 2) {
|
||||
gender = "女";
|
||||
} else {
|
||||
gender = "未知";
|
||||
}
|
||||
|
||||
logger.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());
|
||||
}
|
||||
|
||||
public String bytesToHex(byte[] bytes) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b : bytes) {
|
||||
sb.append(String.format("%02x", b));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void keepRunning() {
|
||||
while (true) {
|
||||
waitMs(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.iamteer;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class Main {
|
||||
private static Logger logger = LoggerFactory.getLogger(Main.class);
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 连接远程 RPC
|
||||
// Client client = new Client("127.0.0.1", 10086);
|
||||
|
||||
// 本地启动 RPC
|
||||
Client client = new Client(true); // 默认 10086 端口
|
||||
// Client client = new Client(10088,true); // 也可以指定端口
|
||||
|
||||
// 是否已登录
|
||||
logger.info("isLogin: {}", client.isLogin());
|
||||
|
||||
// 登录账号 wxid
|
||||
logger.info("wxid: {}", client.getSelfWxid());
|
||||
|
||||
// 消息类型
|
||||
logger.info("message types: {}", client.getMsgTypes());
|
||||
|
||||
// 所有联系人(包括群聊、公众号、好友……)
|
||||
client.printContacts(client.getContacts());
|
||||
|
||||
// 获取数据库
|
||||
logger.info("dbs: {}", client.getDbNames());
|
||||
|
||||
// 获取数据库下的表
|
||||
String db = "MicroMsg.db";
|
||||
logger.info("tables in {}: {}", db, client.getDbTables(db));
|
||||
|
||||
// 发送文本消息,aters 是要 @ 的 wxid,多个用逗号分隔;消息里@的数量要与aters里的数量对应
|
||||
client.sendText("Hello", "filehelper", "");
|
||||
// client.sendText("Hello @某人1 @某人2", "xxxxxxxx@chatroom", "wxid_xxxxxxxxxxxxx1,wxid_xxxxxxxxxxxxx2");
|
||||
|
||||
// 发送图片消息,图片必须要存在
|
||||
client.sendImage("C:\\Projs\\WeChatFerry\\TEQuant.jpeg", "filehelper");
|
||||
|
||||
// 发送文件消息,文件必须要存在
|
||||
client.sendFile("C:\\Projs\\WeChatFerry\\README.MD", "filehelper");
|
||||
|
||||
String xml = "<?xml version=\"1.0\"?><msg><appmsg appid=\"\" sdkver=\"0\"><title>叮当药房,24小时服务,28分钟送药到家!</title><des>叮当快药首家承诺范围内28分钟送药到家!叮当快药核心区域内7*24小时全天候服务,送药上门!叮当快药官网为您提供快捷便利,正品低价,安全放心的购药、送药服务体验。</des><action>view</action><type>33</type><showtype>0</showtype><content /><url>https://mp.weixin.qq.com/mp/waerrpage?appid=wxc2edadc87077fa2a&type=upgrade&upgradetype=3#wechat_redirect</url><dataurl /><lowurl /><lowdataurl /><recorditem /><thumburl /><messageaction /><md5>7f6f49d301ebf47100199b8a4fcf4de4</md5><extinfo /><sourceusername>gh_c2b88a38c424@app</sourceusername><sourcedisplayname>叮当快药 药店送药到家夜间买药</sourcedisplayname><commenturl /><appattach><totallen>0</totallen><attachid /><emoticonmd5></emoticonmd5><fileext>jpg</fileext><filekey>da0e08f5c7259d03da150d5e7ca6d950</filekey><cdnthumburl>3057020100044b30490201000204e4c0232702032f4ef20204a6bace6f02046401f62d042430326337303430352d333734332d343362652d623335322d6233333566623266376334620204012400030201000405004c537600</cdnthumburl><aeskey>0db26456caf243fbd4efb99058a01d66</aeskey><cdnthumbaeskey>0db26456caf243fbd4efb99058a01d66</cdnthumbaeskey><encryver>1</encryver><cdnthumblength>61558</cdnthumblength><cdnthumbheight>100</cdnthumbheight><cdnthumbwidth>100</cdnthumbwidth></appattach><weappinfo><pagepath>pages/index/index.html</pagepath><username>gh_c2b88a38c424@app</username><appid>wxc2edadc87077fa2a</appid><version>197</version><type>2</type><weappiconurl>http://wx.qlogo.cn/mmhead/Q3auHgzwzM4727n0NQ0ZIPQPlfp15m1WLsnrXbo1kLhFGcolgLyc0A/96</weappiconurl><appservicetype>0</appservicetype><shareId>1_wxc2edadc87077fa2a_29177e9a9b918cb9e75964f80bb8f32e_1677849476_0</shareId></weappinfo><websearch /></appmsg><fromusername>wxid_eob5qfcrv4zd22</fromusername><scene>0</scene><appinfo><version>1</version><appname /></appinfo><commenturl /></msg>";
|
||||
client.sendXml("filehelper", xml, "", 0x21);
|
||||
|
||||
// 发送表情消息,gif 必须要存在
|
||||
client.sendEmotion("C:\\Projs\\WeChatFerry\\emo.gif", "filehelper");
|
||||
|
||||
// 接收消息,并调用 printWxMsg 处理
|
||||
client.enableRecvMsg(100);
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
public void run(){while(client.getIsReceivingMsg()){client.printWxMsg(client.getMsg());}}
|
||||
});
|
||||
thread.start();
|
||||
// client.diableRecvMsg(); // 需要停止时调用
|
||||
|
||||
client.keepRunning();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<!-- appender 的配置表示打印到控制台。 -->
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<!-- encoder 默认配置为 PatternLayoutEncoder -->
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="debug">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user