上传备份

master
王兵 4 weeks ago
commit 415d8f738d

20
.gitignore vendored

@ -0,0 +1,20 @@
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
/.idea
*.iml
/.settings
/bin
/gen
/build
/gradle
/classes
.classpath
.project
*.gradle
gradlew
local.properties
node_modules/

@ -0,0 +1,234 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>xyz.wbsite</groupId>
<artifactId>starter-itchat4j</artifactId>
<version>0.1</version>
<packaging>jar</packaging>
<name>starter-itchat4j</name>
<description>project for starter-itchat4j</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>8</java.version>
<maven.test.skip>true</maven.test.skip>
</properties>
<repositories>
<!-- 将中央仓库地址指向阿里云聚合仓库,提高下载速度 -->
<repository>
<id>aliyun</id>
<name>Aliyun Repository</name>
<layout>default</layout>
<url>https://maven.aliyun.com/repository/public</url>
</repository>
</repositories>
<pluginRepositories>
<!-- 将插件的仓库指向阿里云聚合仓库解决低版本maven下载插件异常或提高下载速度 -->
<pluginRepository>
<id>aliyun</id>
<name>Aliyun Repository</name>
<url>https://maven.aliyun.com/repository/public</url>
<layout>default</layout>
</pluginRepository>
</pluginRepositories>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.26</version>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.14.2.1</version>
</dependency>
<!-- java注册全局热键 -->
<dependency>
<groupId>com.melloware</groupId>
<artifactId>jintellitype</artifactId>
<version>1.4.0</version>
</dependency>
<!-- 以下是itchat4j的依赖 -->
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.31</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.0</version>
</dependency>
<!-- emoji -->
<dependency>
<groupId>com.vdurmont</groupId>
<artifactId>emoji-java</artifactId>
<version>3.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.activation/activation -->
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.6</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.8.0</version>
</dependency>
</dependencies>
<build>
<finalName>${artifactId}-${version}</finalName>
<sourceDirectory>src/main/java</sourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<!-- 打包可执行文件 -->
<plugin>
<groupId>com.zenjava</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>8.8.3</version>
<configuration>
<!-- 启动类 -->
<mainClass>xyz.wbsite.itchat4j.JMainApplication</mainClass>
<!-- 公司名称 -->
<vendor>${project.artifactId}</vendor>
<!-- 应用名称 ${project.build.finalName} = ${project.artifactId}-${project.version} -->
<appName>${project.artifactId}</appName>
<!-- 编译后的jfx/app下的jar包名称 -->
<jfxMainAppJarName>${project.artifactId}.jar</jfxMainAppJarName>
<!-- 发行版本 -->
<nativeReleaseVersion>${project.version}</nativeReleaseVersion>
<!--
图标设置
> 参考https://stackoverflow.com/questions/15880102/how-to-set-custom-icon-for-javafx-native-package-icon-on-windows
# 方式1按deployDir、appName配置读取ico文件
# 使用jfx:native打包时默认会去src/main/deploy/package/windows/${appName}.ico
<deployDir>${project.basedir}/src/main/deploy</deployDir>
# 方式2固定使用一个图标与版本号无关
# 优先级高于第一种方式
<bundleArguments>
<icon>${project.basedir}/src/main/resources/icon/icon.ico</icon>
</bundleArguments>
-->
<bundleArguments>
<icon>${project.basedir}/src/main/resources/icon.ico</icon>
</bundleArguments>
<!-- 桌面图标 -->
<needShortcut>true</needShortcut>
<!-- 菜单设置 -->
<needMenu>true</needMenu>
</configuration>
<executions>
<execution>
<id>create-jfx-jar</id>
<phase>package</phase>
<goals>
<goal>build-jar</goal>
</goals>
</execution>
<execution>
<id>create-exe</id>
<phase>package</phase>
<goals>
<goal>build-native</goal>
</goals>
</execution>
</executions>
</plugin>
<!--处理图例文件-->
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<move file="${project.build.directory}/jfx/native/${project.artifactId}"
tofile="${project.build.directory}/${project.artifactId}-${project.version}"/>
<copydir src="${project.basedir}/legend"
dest="${project.build.directory}/${project.artifactId}-${project.version}/app/legend"/>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,33 @@
package cn.zhouyafeng.itchat4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cn.zhouyafeng.itchat4j.controller.LoginController;
import cn.zhouyafeng.itchat4j.core.MsgCenter;
import cn.zhouyafeng.itchat4j.face.IMsgHandlerFace;
public class Wechat {
private static final Logger LOG = LoggerFactory.getLogger(Wechat.class);
private IMsgHandlerFace msgHandler;
public Wechat(IMsgHandlerFace msgHandler, String qrPath) {
System.setProperty("jsse.enableSNIExtension", "false"); // 防止SSL错误
this.msgHandler = msgHandler;
// 登陆
LoginController login = new LoginController();
login.login(qrPath);
}
public void start() {
LOG.info("+++++++++++++++++++开始消息处理+++++++++++++++++++++");
new Thread(new Runnable() {
@Override
public void run() {
MsgCenter.handleMsg(msgHandler);
}
}).start();
}
}

@ -0,0 +1,43 @@
package cn.zhouyafeng.itchat4j.api;
import java.io.File;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
*
*
* @author https://github.com/yaphone
* @date 2017522 10:34:46
* @version 1.0
*
*/
public class AssistTools {
private static OkHttpClient client = new OkHttpClient();
private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
public static boolean sendQrPicToServer(String username, String password, String uploadUrl, String localPath)
throws IOException {
File file = new File(localPath);
RequestBody requestBody = new MultipartBody.Builder().addFormDataPart("username", username)
.addFormDataPart("password", password)
.addFormDataPart("file", file.getName(), RequestBody.create(MEDIA_TYPE_PNG, file)).build();
Request request = new Request.Builder().url(uploadUrl).post(requestBody).build();
Call call = client.newCall(request);
try {
Response response = call.execute();
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
}

@ -0,0 +1,424 @@
package cn.zhouyafeng.itchat4j.api;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.activation.MimetypesFileTypeMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import cn.zhouyafeng.itchat4j.beans.BaseMsg;
import cn.zhouyafeng.itchat4j.beans.RecommendInfo;
import cn.zhouyafeng.itchat4j.core.Core;
import cn.zhouyafeng.itchat4j.utils.Config;
import cn.zhouyafeng.itchat4j.utils.MyHttpClient;
import cn.zhouyafeng.itchat4j.utils.enums.StorageLoginInfoEnum;
import cn.zhouyafeng.itchat4j.utils.enums.URLEnum;
import cn.zhouyafeng.itchat4j.utils.enums.VerifyFriendEnum;
/**
*
*
* @author https://github.com/yaphone
* @date 2017423 2:30:37
* @version 1.0
*
*/
public class MessageTools {
private static Logger LOG = LoggerFactory.getLogger(MessageTools.class);
private static Core core = Core.getInstance();
private static MyHttpClient myHttpClient = core.getMyHttpClient();
/**
* UserName
*
* @author https://github.com/yaphone
* @date 201754 11:17:38
* @param msg
* @param toUserName
*/
private static void sendMsg(String text, String toUserName) {
if (text == null) {
return;
}
LOG.info(String.format("发送消息 %s: %s", toUserName, text));
webWxSendMsg(1, text, toUserName);
}
/**
* ID
*
* @author https://github.com/yaphone
* @date 201756 11:45:51
* @param text
* @param id
*/
public static void sendMsgById(String text, String id) {
if (text == null) {
return;
}
sendMsg(text, id);
}
/**
* NickName
*
* @author https://github.com/yaphone
* @date 201754 11:17:38
* @param text
* @param nickName
*/
public static boolean sendMsgByNickName(String text, String nickName) {
if (nickName != null) {
String toUserName = WechatTools.getUserNameByNickName(nickName);
if (toUserName != null) {
webWxSendMsg(1, text, toUserName);
return true;
}
}
return false;
}
/**
*
*
* @author https://github.com/yaphone
* @date 2017423 2:32:02
* @param msgType
* @param content
* @param toUserName
*/
public static void webWxSendMsg(int msgType, String content, String toUserName) {
String url = String.format(URLEnum.WEB_WX_SEND_MSG.getUrl(), core.getLoginInfo().get("url"));
Map<String, Object> msgMap = new HashMap<String, Object>();
msgMap.put("Type", msgType);
msgMap.put("Content", content);
msgMap.put("FromUserName", core.getUserName());
msgMap.put("ToUserName", toUserName == null ? core.getUserName() : toUserName);
msgMap.put("LocalID", new Date().getTime() * 10);
msgMap.put("ClientMsgId", new Date().getTime() * 10);
Map<String, Object> paramMap = core.getParamMap();
paramMap.put("Msg", msgMap);
paramMap.put("Scene", 0);
try {
String paramStr = JSON.toJSONString(paramMap);
HttpEntity entity = myHttpClient.doPost(url, paramStr);
EntityUtils.toString(entity, Consts.UTF_8);
} catch (Exception e) {
LOG.error("webWxSendMsg", e);
}
}
/**
* 3: 1. pic 2.video 3.doc PDF
*
* @author https://github.com/yaphone
* @date 201757 12:41:13
* @param filePath
* @return
*/
private static JSONObject webWxUploadMedia(String filePath) {
File f = new File(filePath);
if (!f.exists() && f.isFile()) {
LOG.info("file is not exist");
return null;
}
String url = String.format(URLEnum.WEB_WX_UPLOAD_MEDIA.getUrl(), core.getLoginInfo().get("fileUrl"));
String mimeType = new MimetypesFileTypeMap().getContentType(f);
String mediaType = "";
if (mimeType == null) {
mimeType = "text/plain";
} else {
mediaType = mimeType.split("/")[0].equals("image") ? "pic" : "doc";
}
String lastModifieDate = new SimpleDateFormat("yyyy MM dd HH:mm:ss").format(new Date());
long fileSize = f.length();
String passTicket = (String) core.getLoginInfo().get("pass_ticket");
String clientMediaId = String.valueOf(new Date().getTime())
+ String.valueOf(new Random().nextLong()).substring(0, 4);
String webwxDataTicket = MyHttpClient.getCookie("webwx_data_ticket");
if (webwxDataTicket == null) {
LOG.error("get cookie webwx_data_ticket error");
return null;
}
Map<String, Object> paramMap = core.getParamMap();
paramMap.put("ClientMediaId", clientMediaId);
paramMap.put("TotalLen", fileSize);
paramMap.put("StartPos", 0);
paramMap.put("DataLen", fileSize);
paramMap.put("MediaType", 4);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addTextBody("id", "WU_FILE_0", ContentType.TEXT_PLAIN);
builder.addTextBody("name", filePath, ContentType.TEXT_PLAIN);
builder.addTextBody("type", mimeType, ContentType.TEXT_PLAIN);
builder.addTextBody("lastModifieDate", lastModifieDate, ContentType.TEXT_PLAIN);
builder.addTextBody("size", String.valueOf(fileSize), ContentType.TEXT_PLAIN);
builder.addTextBody("mediatype", mediaType, ContentType.TEXT_PLAIN);
builder.addTextBody("uploadmediarequest", JSON.toJSONString(paramMap), ContentType.TEXT_PLAIN);
builder.addTextBody("webwx_data_ticket", webwxDataTicket, ContentType.TEXT_PLAIN);
builder.addTextBody("pass_ticket", passTicket, ContentType.TEXT_PLAIN);
builder.addBinaryBody("filename", f, ContentType.create(mimeType), filePath);
HttpEntity reqEntity = builder.build();
HttpEntity entity = myHttpClient.doPostFile(url, reqEntity);
if (entity != null) {
try {
String result = EntityUtils.toString(entity, Consts.UTF_8);
return JSON.parseObject(result);
} catch (Exception e) {
LOG.error("webWxUploadMedia 错误: ", e);
}
}
return null;
}
/**
* NickName
*
* @author https://github.com/yaphone
* @date 201757 10:32:45
* @param nackName
* @return
*/
public static boolean sendPicMsgByNickName(String nickName, String filePath) {
String toUserName = WechatTools.getUserNameByNickName(nickName);
if (toUserName != null) {
return sendPicMsgByUserId(toUserName, filePath);
}
return false;
}
/**
* id
*
* @author https://github.com/yaphone
* @date 201757 10:34:24
* @param nickName
* @param filePath
* @return
*/
public static boolean sendPicMsgByUserId(String userId, String filePath) {
JSONObject responseObj = webWxUploadMedia(filePath);
if (responseObj != null) {
String mediaId = responseObj.getString("MediaId");
if (mediaId != null) {
return webWxSendMsgImg(userId, mediaId);
}
}
return false;
}
/**
*
*
* @author https://github.com/yaphone
* @date 201757 10:38:55
* @return
*/
private static boolean webWxSendMsgImg(String userId, String mediaId) {
String url = String.format("%s/webwxsendmsgimg?fun=async&f=json&pass_ticket=%s", core.getLoginInfo().get("url"),
core.getLoginInfo().get("pass_ticket"));
Map<String, Object> msgMap = new HashMap<String, Object>();
msgMap.put("Type", 3);
msgMap.put("MediaId", mediaId);
msgMap.put("FromUserName", core.getUserSelf().getString("UserName"));
msgMap.put("ToUserName", userId);
String clientMsgId = String.valueOf(new Date().getTime())
+ String.valueOf(new Random().nextLong()).substring(1, 5);
msgMap.put("LocalID", clientMsgId);
msgMap.put("ClientMsgId", clientMsgId);
Map<String, Object> paramMap = core.getParamMap();
paramMap.put("BaseRequest", core.getParamMap().get("BaseRequest"));
paramMap.put("Msg", msgMap);
String paramStr = JSON.toJSONString(paramMap);
HttpEntity entity = myHttpClient.doPost(url, paramStr);
if (entity != null) {
try {
String result = EntityUtils.toString(entity, Consts.UTF_8);
return JSON.parseObject(result).getJSONObject("BaseResponse").getInteger("Ret") == 0;
} catch (Exception e) {
LOG.error("webWxSendMsgImg 错误: ", e);
}
}
return false;
}
/**
* id
*
* @author https://github.com/yaphone
* @date 201757 11:57:36
* @param userId
* @param filePath
* @return
*/
public static boolean sendFileMsgByUserId(String userId, String filePath) {
String title = new File(filePath).getName();
Map<String, String> data = new HashMap<String, String>();
data.put("appid", Config.API_WXAPPID);
data.put("title", title);
data.put("totallen", "");
data.put("attachid", "");
data.put("type", "6"); // APPMSGTYPE_ATTACH
data.put("fileext", title.split("\\.")[1]); // 文件后缀
JSONObject responseObj = webWxUploadMedia(filePath);
if (responseObj != null) {
data.put("totallen", responseObj.getString("StartPos"));
data.put("attachid", responseObj.getString("MediaId"));
} else {
LOG.error("sednFileMsgByUserId 错误: ", data);
}
return webWxSendAppMsg(userId, data);
}
/**
*
*
* @author https://github.com/yaphone
* @date 2017510 10:59:27
* @param nickName
* @param filePath
* @return
*/
public static boolean sendFileMsgByNickName(String nickName, String filePath) {
String toUserName = WechatTools.getUserNameByNickName(nickName);
if (toUserName != null) {
return sendFileMsgByUserId(toUserName, filePath);
}
return false;
}
/**
*
*
* @author https://github.com/yaphone
* @date 2017510 12:21:28
* @param userId
* @param data
* @return
*/
private static boolean webWxSendAppMsg(String userId, Map<String, String> data) {
String url = String.format("%s/webwxsendappmsg?fun=async&f=json&pass_ticket=%s", core.getLoginInfo().get("url"),
core.getLoginInfo().get("pass_ticket"));
String clientMsgId = String.valueOf(new Date().getTime())
+ String.valueOf(new Random().nextLong()).substring(1, 5);
String content = "<appmsg appid='wxeb7ec651dd0aefa9' sdkver=''><title>" + data.get("title")
+ "</title><des></des><action></action><type>6</type><content></content><url></url><lowurl></lowurl>"
+ "<appattach><totallen>" + data.get("totallen") + "</totallen><attachid>" + data.get("attachid")
+ "</attachid><fileext>" + data.get("fileext") + "</fileext></appattach><extinfo></extinfo></appmsg>";
Map<String, Object> msgMap = new HashMap<String, Object>();
msgMap.put("Type", data.get("type"));
msgMap.put("Content", content);
msgMap.put("FromUserName", core.getUserSelf().getString("UserName"));
msgMap.put("ToUserName", userId);
msgMap.put("LocalID", clientMsgId);
msgMap.put("ClientMsgId", clientMsgId);
/*
* Map<String, Object> paramMap = new HashMap<String, Object>();
*
* @SuppressWarnings("unchecked") Map<String, Map<String, String>>
* baseRequestMap = (Map<String, Map<String, String>>)
* core.getLoginInfo() .get("baseRequest"); paramMap.put("BaseRequest",
* baseRequestMap.get("BaseRequest"));
*/
Map<String, Object> paramMap = core.getParamMap();
paramMap.put("Msg", msgMap);
paramMap.put("Scene", 0);
String paramStr = JSON.toJSONString(paramMap);
HttpEntity entity = myHttpClient.doPost(url, paramStr);
if (entity != null) {
try {
String result = EntityUtils.toString(entity, Consts.UTF_8);
return JSON.parseObject(result).getJSONObject("BaseResponse").getInteger("Ret") == 0;
} catch (Exception e) {
LOG.error("错误: ", e);
}
}
return false;
}
/**
*
*
* @date 2017629 10:08:43
* @param msg
* @param accept
* true false
*/
public static void addFriend(BaseMsg msg, boolean accept) {
if (!accept) { // 不添加
return;
}
int status = VerifyFriendEnum.ACCEPT.getCode(); // 接受好友请求
RecommendInfo recommendInfo = msg.getRecommendInfo();
String userName = recommendInfo.getUserName();
String ticket = recommendInfo.getTicket();
// 更新好友列表
// TODO 此处需要更新好友列表
// core.getContactList().add(msg.getJSONObject("RecommendInfo"));
String url = String.format(URLEnum.WEB_WX_VERIFYUSER.getUrl(), core.getLoginInfo().get("url"),
String.valueOf(System.currentTimeMillis() / 3158L), core.getLoginInfo().get("pass_ticket"));
List<Map<String, Object>> verifyUserList = new ArrayList<Map<String, Object>>();
Map<String, Object> verifyUser = new HashMap<String, Object>();
verifyUser.put("Value", userName);
verifyUser.put("VerifyUserTicket", ticket);
verifyUserList.add(verifyUser);
List<Integer> sceneList = new ArrayList<Integer>();
sceneList.add(33);
JSONObject body = new JSONObject();
body.put("BaseRequest", core.getParamMap().get("BaseRequest"));
body.put("Opcode", status);
body.put("VerifyUserListSize", 1);
body.put("VerifyUserList", verifyUserList);
body.put("VerifyContent", "");
body.put("SceneListCount", 1);
body.put("SceneList", sceneList);
body.put("skey", core.getLoginInfo().get(StorageLoginInfoEnum.skey.getKey()));
String result = null;
try {
String paramStr = JSON.toJSONString(body);
HttpEntity entity = myHttpClient.doPost(url, paramStr);
result = EntityUtils.toString(entity, Consts.UTF_8);
} catch (Exception e) {
LOG.error("webWxSendMsg", e);
}
if (StringUtils.isBlank(result)) {
LOG.error("被动添加好友失败");
}
LOG.debug(result);
}
}

@ -0,0 +1,215 @@
package cn.zhouyafeng.itchat4j.api;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import cn.zhouyafeng.itchat4j.core.Core;
import cn.zhouyafeng.itchat4j.utils.enums.StorageLoginInfoEnum;
import cn.zhouyafeng.itchat4j.utils.enums.URLEnum;
/**
*
*
* @author https://github.com/yaphone
* @date 201754 10:49:16
* @version 1.0
*
*/
public class WechatTools {
private static Logger LOG = LoggerFactory.getLogger(WechatTools.class);
private static Core core = Core.getInstance();
/**
*
*
* @author https://github.com/yaphone
* @date 201754 10:43:14
* @param msg
* @param toUserName
*/
public static void sendMsgByUserName(String msg, String toUserName) {
MessageTools.sendMsgById(msg, toUserName);
}
/**
* <p>
* RealNameUserName
* </p>
* <p>
* NickName"yaphone"UserName=
* "@1212d3356aea8285e5bbe7b91229936bc183780a8ffa469f2d638bf0d2e4fc63"
* UserName
* </p>
*
* @author https://github.com/yaphone
* @date 201754 10:56:31
* @param name
* @return
*/
public static String getUserNameByNickName(String nickName) {
for (JSONObject o : core.getContactList()) {
if (o.getString("NickName").equals(nickName)) {
return o.getString("UserName");
}
}
return null;
}
/**
*
*
* @author https://github.com/yaphone
* @date 201754 11:37:20
* @return
*/
public static List<String> getContactNickNameList() {
List<String> contactNickNameList = new ArrayList<String>();
for (JSONObject o : core.getContactList()) {
contactNickNameList.add(o.getString("NickName"));
}
return contactNickNameList;
}
/**
*
*
* @date 2017626 9:45:39
* @return
*/
public static List<JSONObject> getContactList() {
return core.getContactList();
}
/**
*
*
* @author https://github.com/yaphone
* @date 201755 9:55:21
* @return
*/
public static List<JSONObject> getGroupList() {
return core.getGroupList();
}
/**
* ID
*
* @date 2017621 11:42:56
* @return
*/
public static List<String> getGroupIdList() {
return core.getGroupIdList();
}
/**
* NickName
*
* @date 2017621 11:43:38
* @return
*/
public static List<String> getGroupNickNameList() {
return core.getGroupNickNameList();
}
/**
* groupIdList
*
* @date 2017613 11:12:31
* @param groupId
* @return
*/
public static JSONArray getMemberListByGroupId(String groupId) {
return core.getGroupMemeberMap().get(groupId);
}
/**
* 退
*
* @author https://github.com/yaphone
* @date 2017518 11:56:54
*/
public static void logout() {
webWxLogout();
}
private static boolean webWxLogout() {
String url = String.format(URLEnum.WEB_WX_LOGOUT.getUrl(),
core.getLoginInfo().get(StorageLoginInfoEnum.url.getKey()));
List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
params.add(new BasicNameValuePair("redirect", "1"));
params.add(new BasicNameValuePair("type", "1"));
params.add(
new BasicNameValuePair("skey", (String) core.getLoginInfo().get(StorageLoginInfoEnum.skey.getKey())));
try {
HttpEntity entity = core.getMyHttpClient().doGet(url, params, false, null);
String text = EntityUtils.toString(entity, Consts.UTF_8); // 无消息
return true;
} catch (Exception e) {
LOG.debug(e.getMessage());
}
return false;
}
public static void setUserInfo() {
for (JSONObject o : core.getContactList()) {
core.getUserInfoMap().put(o.getString("NickName"), o);
core.getUserInfoMap().put(o.getString("UserName"), o);
}
}
/**
*
*
*
* @date 2017527 12:21:40
* @param userName
* @param remName
*/
public static void remarkNameByNickName(String nickName, String remName) {
String url = String.format(URLEnum.WEB_WX_REMARKNAME.getUrl(), core.getLoginInfo().get("url"),
core.getLoginInfo().get(StorageLoginInfoEnum.pass_ticket.getKey()));
Map<String, Object> msgMap = new HashMap<String, Object>();
Map<String, Object> msgMap_BaseRequest = new HashMap<String, Object>();
msgMap.put("CmdId", 2);
msgMap.put("RemarkName", remName);
msgMap.put("UserName", core.getUserInfoMap().get(nickName).get("UserName"));
msgMap_BaseRequest.put("Uin", core.getLoginInfo().get(StorageLoginInfoEnum.wxuin.getKey()));
msgMap_BaseRequest.put("Sid", core.getLoginInfo().get(StorageLoginInfoEnum.wxsid.getKey()));
msgMap_BaseRequest.put("Skey", core.getLoginInfo().get(StorageLoginInfoEnum.skey.getKey()));
msgMap_BaseRequest.put("DeviceID", core.getLoginInfo().get(StorageLoginInfoEnum.deviceid.getKey()));
msgMap.put("BaseRequest", msgMap_BaseRequest);
try {
String paramStr = JSON.toJSONString(msgMap);
HttpEntity entity = core.getMyHttpClient().doPost(url, paramStr);
// String result = EntityUtils.toString(entity, Consts.UTF_8);
LOG.info("修改备注" + remName);
} catch (Exception e) {
LOG.error("remarkNameByUserName", e);
}
}
/**
* 线
*
* @date 2017616 12:47:46
* @return
*/
public static boolean getWechatStatus() {
return core.isAlive();
}
}

@ -0,0 +1,37 @@
package cn.zhouyafeng.itchat4j.beans;
import java.io.Serializable;
/**
* AppInfo
*
* @author https://github.com/yaphone
* @date 201773 10:38:14
* @version 1.0
*
*/
public class AppInfo implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private int type;
private String appId;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
}

@ -0,0 +1,293 @@
package cn.zhouyafeng.itchat4j.beans;
import java.io.Serializable;
/**
*
*
* @author https://github.com/yaphone
* @date 201773 10:28:06
* @version 1.0
*
*/
public class BaseMsg implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private int subMsgType;
private int voiceLength;
private String fileName;
private int imgHeight;
private String toUserName;
private int hasProductId;
private int imgStatus;
private String url;
private int imgWidth;
private int forwardFlag;
private int status;
private String Ticket;
/** 推荐消息报文 **/
private RecommendInfo recommendInfo;
private long createTime;
private String newMsgId;
/** 文本消息内容 **/
private String text;
/** 消息类型 **/
private int msgType;
/** 是否为群消息 **/
private boolean groupMsg;
private String msgId;
private int statusNotifyCode;
private AppInfo appInfo;
private int appMsgType;
private String Type;
private int playLength;
private String mediaId;
private String content;
private String statusNotifyUserName;
/** 消息发送者ID **/
private String fromUserName;
private String oriContent;
private String fileSize;
public int getSubMsgType() {
return subMsgType;
}
public void setSubMsgType(int subMsgType) {
this.subMsgType = subMsgType;
}
public int getVoiceLength() {
return voiceLength;
}
public void setVoiceLength(int voiceLength) {
this.voiceLength = voiceLength;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public int getImgHeight() {
return imgHeight;
}
public void setImgHeight(int imgHeight) {
this.imgHeight = imgHeight;
}
public String getToUserName() {
return toUserName;
}
public void setToUserName(String toUserName) {
this.toUserName = toUserName;
}
public int getHasProductId() {
return hasProductId;
}
public void setHasProductId(int hasProductId) {
this.hasProductId = hasProductId;
}
public int getImgStatus() {
return imgStatus;
}
public void setImgStatus(int imgStatus) {
this.imgStatus = imgStatus;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getImgWidth() {
return imgWidth;
}
public void setImgWidth(int imgWidth) {
this.imgWidth = imgWidth;
}
public int getForwardFlag() {
return forwardFlag;
}
public void setForwardFlag(int forwardFlag) {
this.forwardFlag = forwardFlag;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getTicket() {
return Ticket;
}
public void setTicket(String ticket) {
Ticket = ticket;
}
public RecommendInfo getRecommendInfo() {
return recommendInfo;
}
public void setRecommendInfo(RecommendInfo recommendInfo) {
this.recommendInfo = recommendInfo;
}
public long getCreateTime() {
return createTime;
}
public void setCreateTime(long createTime) {
this.createTime = createTime;
}
public String getNewMsgId() {
return newMsgId;
}
public void setNewMsgId(String newMsgId) {
this.newMsgId = newMsgId;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public int getMsgType() {
return msgType;
}
public void setMsgType(int msgType) {
this.msgType = msgType;
}
public boolean isGroupMsg() {
return groupMsg;
}
public void setGroupMsg(boolean groupMsg) {
this.groupMsg = groupMsg;
}
public String getMsgId() {
return msgId;
}
public void setMsgId(String msgId) {
this.msgId = msgId;
}
public int getStatusNotifyCode() {
return statusNotifyCode;
}
public void setStatusNotifyCode(int statusNotifyCode) {
this.statusNotifyCode = statusNotifyCode;
}
public AppInfo getAppInfo() {
return appInfo;
}
public void setAppInfo(AppInfo appInfo) {
this.appInfo = appInfo;
}
public int getAppMsgType() {
return appMsgType;
}
public void setAppMsgType(int appMsgType) {
this.appMsgType = appMsgType;
}
public String getType() {
return Type;
}
public void setType(String type) {
Type = type;
}
public int getPlayLength() {
return playLength;
}
public void setPlayLength(int playLength) {
this.playLength = playLength;
}
public String getMediaId() {
return mediaId;
}
public void setMediaId(String mediaId) {
this.mediaId = mediaId;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getStatusNotifyUserName() {
return statusNotifyUserName;
}
public void setStatusNotifyUserName(String statusNotifyUserName) {
this.statusNotifyUserName = statusNotifyUserName;
}
public String getFromUserName() {
return fromUserName;
}
public void setFromUserName(String fromUserName) {
this.fromUserName = fromUserName;
}
public String getOriContent() {
return oriContent;
}
public void setOriContent(String oriContent) {
this.oriContent = oriContent;
}
public String getFileSize() {
return fileSize;
}
public void setFileSize(String fileSize) {
this.fileSize = fileSize;
}
}

@ -0,0 +1,146 @@
package cn.zhouyafeng.itchat4j.beans;
import java.io.Serializable;
/**
* RecommendInfo
*
* @author https://github.com/yaphone
* @date 201773 10:35:14
* @version 1.0
*
*/
public class RecommendInfo implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private String ticket;
private String userName;
private int sex;
private int attrStatus;
private String city;
private String nickName;
private int scene;
private String province;
private String content;
private String alias;
private String signature;
private int opCode;
private int qQNum;
private int verifyFlag;
public String getTicket() {
return ticket;
}
public void setTicket(String ticket) {
this.ticket = ticket;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public int getAttrStatus() {
return attrStatus;
}
public void setAttrStatus(int attrStatus) {
this.attrStatus = attrStatus;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public int getScene() {
return scene;
}
public void setScene(int scene) {
this.scene = scene;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias = alias;
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}
public int getOpCode() {
return opCode;
}
public void setOpCode(int opCode) {
this.opCode = opCode;
}
public int getqQNum() {
return qQNum;
}
public void setqQNum(int qQNum) {
this.qQNum = qQNum;
}
public int getVerifyFlag() {
return verifyFlag;
}
public void setVerifyFlag(int verifyFlag) {
this.verifyFlag = verifyFlag;
}
}

@ -0,0 +1,88 @@
package cn.zhouyafeng.itchat4j.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cn.zhouyafeng.itchat4j.api.WechatTools;
import cn.zhouyafeng.itchat4j.core.Core;
import cn.zhouyafeng.itchat4j.service.ILoginService;
import cn.zhouyafeng.itchat4j.service.impl.LoginServiceImpl;
import cn.zhouyafeng.itchat4j.thread.CheckLoginStatusThread;
import cn.zhouyafeng.itchat4j.utils.SleepUtils;
import cn.zhouyafeng.itchat4j.utils.tools.CommonTools;
/**
*
*
* @author https://github.com/yaphone
* @date 2017513 12:56:07
* @version 1.0
*
*/
public class LoginController {
private static Logger LOG = LoggerFactory.getLogger(LoginController.class);
private ILoginService loginService = new LoginServiceImpl();
private static Core core = Core.getInstance();
public void login(String qrPath) {
if (core.isAlive()) { // 已登陆
LOG.info("itchat4j已登陆");
return;
}
while (true) {
for (int count = 0; count <= 10; count++) {
LOG.info("获取UUID");
while (loginService.getUuid() == null) {
LOG.info("1. 获取微信UUID");
while (loginService.getUuid() == null) {
LOG.warn("1.1. 获取微信UUID失败两秒后重新获取");
SleepUtils.sleep(2000);
}
}
LOG.info("2. 获取登陆二维码图片");
if (loginService.getQR(qrPath)) {
break;
} else if (count == 10) {
LOG.error("2.2. 获取登陆二维码图片失败,系统退出");
System.exit(0);
}
}
LOG.info("3. 请扫描二维码图片,并在手机上确认");
if (!core.isAlive()) {
loginService.login();
core.setAlive(true);
LOG.info(("登陆成功"));
break;
}
LOG.info("4. 登陆超时,请重新扫描二维码图片");
}
LOG.info("5. 登陆成功,微信初始化");
if (!loginService.webWxInit()) {
LOG.info("6. 微信初始化异常");
System.exit(0);
}
LOG.info("6. 开启微信状态通知");
loginService.wxStatusNotify();
LOG.info("7. 清除。。。。");
CommonTools.clearScreen();
LOG.info(String.format("欢迎回来, %s", core.getNickName()));
LOG.info("8. 开始接收消息");
loginService.startReceiving();
LOG.info("9. 获取联系人信息");
loginService.webWxGetContact();
LOG.info("10. 获取群好友及群好友列表");
loginService.WebWxBatchGetContact();
LOG.info("11. 缓存本次登陆好友相关消息");
WechatTools.setUserInfo(); // 登陆成功后缓存本次登陆好友相关消息NickName, UserName
LOG.info("12.开启微信状态检测线程");
new Thread(new CheckLoginStatusThread()).start();
}
}

@ -0,0 +1,276 @@
package cn.zhouyafeng.itchat4j.core;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import cn.zhouyafeng.itchat4j.beans.BaseMsg;
import cn.zhouyafeng.itchat4j.utils.MyHttpClient;
import cn.zhouyafeng.itchat4j.utils.enums.parameters.BaseParaEnum;
/**
*
*
* @author https://github.com/yaphone
* @date 2017423 2:33:56
* @version 1.0
*
*/
public class Core {
private static Core instance;
private Core() {
}
public static Core getInstance() {
if (instance == null) {
synchronized (Core.class) {
instance = new Core();
}
}
return instance;
}
boolean alive = false;
private int memberCount = 0;
private String indexUrl;
private String userName;
private String nickName;
private List<BaseMsg> msgList = new ArrayList<BaseMsg>();
private JSONObject userSelf; // 登陆账号自身信息
private List<JSONObject> memberList = new ArrayList<JSONObject>(); // 好友+群聊+公众号+特殊账号
private List<JSONObject> contactList = new ArrayList<JSONObject>();// 好友
private List<JSONObject> groupList = new ArrayList<JSONObject>();; // 群
private Map<String, JSONArray> groupMemeberMap = new HashMap<String, JSONArray>(); // 群聊成员字典
private List<JSONObject> publicUsersList = new ArrayList<JSONObject>();;// 公众号/服务号
private List<JSONObject> specialUsersList = new ArrayList<JSONObject>();;// 特殊账号
private List<String> groupIdList = new ArrayList<String>(); // 群ID列表
private List<String> groupNickNameList = new ArrayList<String>(); // 群NickName列表
private Map<String, JSONObject> userInfoMap = new HashMap<String, JSONObject>();
Map<String, Object> loginInfo = new HashMap<String, Object>();
// CloseableHttpClient httpClient = HttpClients.createDefault();
MyHttpClient myHttpClient = MyHttpClient.getInstance();
String uuid = null;
boolean useHotReload = false;
String hotReloadDir = "itchat.pkl";
int receivingRetryCount = 5;
private long lastNormalRetcodeTime; // 最后一次收到正常retcode的时间秒为单位
/**
*
*/
public Map<String, Object> getParamMap() {
return new HashMap<String, Object>(1) {
/**
*
*/
private static final long serialVersionUID = 1L;
{
Map<String, String> map = new HashMap<String, String>();
for (BaseParaEnum baseRequest : BaseParaEnum.values()) {
map.put(baseRequest.para(), getLoginInfo().get(baseRequest.value()).toString());
}
put("BaseRequest", map);
}
};
}
public boolean isAlive() {
return alive;
}
public void setAlive(boolean alive) {
this.alive = alive;
}
public List<JSONObject> getMemberList() {
return memberList;
}
public void setMemberList(List<JSONObject> memberList) {
this.memberList = memberList;
}
public Map<String, Object> getLoginInfo() {
return loginInfo;
}
public void setLoginInfo(Map<String, Object> loginInfo) {
this.loginInfo = loginInfo;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public int getMemberCount() {
return memberCount;
}
public void setMemberCount(int memberCount) {
this.memberCount = memberCount;
}
public boolean isUseHotReload() {
return useHotReload;
}
public void setUseHotReload(boolean useHotReload) {
this.useHotReload = useHotReload;
}
public String getHotReloadDir() {
return hotReloadDir;
}
public void setHotReloadDir(String hotReloadDir) {
this.hotReloadDir = hotReloadDir;
}
public int getReceivingRetryCount() {
return receivingRetryCount;
}
public void setReceivingRetryCount(int receivingRetryCount) {
this.receivingRetryCount = receivingRetryCount;
}
public MyHttpClient getMyHttpClient() {
return myHttpClient;
}
public List<BaseMsg> getMsgList() {
return msgList;
}
public void setMsgList(List<BaseMsg> msgList) {
this.msgList = msgList;
}
public void setMyHttpClient(MyHttpClient myHttpClient) {
this.myHttpClient = myHttpClient;
}
public List<String> getGroupIdList() {
return groupIdList;
}
public void setGroupIdList(List<String> groupIdList) {
this.groupIdList = groupIdList;
}
public List<JSONObject> getContactList() {
return contactList;
}
public void setContactList(List<JSONObject> contactList) {
this.contactList = contactList;
}
public List<JSONObject> getGroupList() {
return groupList;
}
public void setGroupList(List<JSONObject> groupList) {
this.groupList = groupList;
}
public List<JSONObject> getPublicUsersList() {
return publicUsersList;
}
public void setPublicUsersList(List<JSONObject> publicUsersList) {
this.publicUsersList = publicUsersList;
}
public List<JSONObject> getSpecialUsersList() {
return specialUsersList;
}
public void setSpecialUsersList(List<JSONObject> specialUsersList) {
this.specialUsersList = specialUsersList;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public JSONObject getUserSelf() {
return userSelf;
}
public void setUserSelf(JSONObject userSelf) {
this.userSelf = userSelf;
}
public Map<String, JSONObject> getUserInfoMap() {
return userInfoMap;
}
public void setUserInfoMap(Map<String, JSONObject> userInfoMap) {
this.userInfoMap = userInfoMap;
}
public synchronized long getLastNormalRetcodeTime() {
return lastNormalRetcodeTime;
}
public synchronized void setLastNormalRetcodeTime(long lastNormalRetcodeTime) {
this.lastNormalRetcodeTime = lastNormalRetcodeTime;
}
public List<String> getGroupNickNameList() {
return groupNickNameList;
}
public void setGroupNickNameList(List<String> groupNickNameList) {
this.groupNickNameList = groupNickNameList;
}
public Map<String, JSONArray> getGroupMemeberMap() {
return groupMemeberMap;
}
public void setGroupMemeberMap(Map<String, JSONArray> groupMemeberMap) {
this.groupMemeberMap = groupMemeberMap;
}
public String getIndexUrl() {
return indexUrl;
}
public void setIndexUrl(String indexUrl) {
this.indexUrl = indexUrl;
}
}

@ -0,0 +1,170 @@
package cn.zhouyafeng.itchat4j.core;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import cn.zhouyafeng.itchat4j.api.MessageTools;
import cn.zhouyafeng.itchat4j.beans.BaseMsg;
import cn.zhouyafeng.itchat4j.face.IMsgHandlerFace;
import cn.zhouyafeng.itchat4j.utils.enums.MsgCodeEnum;
import cn.zhouyafeng.itchat4j.utils.enums.MsgTypeEnum;
import cn.zhouyafeng.itchat4j.utils.tools.CommonTools;
/**
*
*
* @author https://github.com/yaphone
* @date 2017514 12:47:50
* @version 1.0
*
*/
public class MsgCenter {
private static Logger LOG = LoggerFactory.getLogger(MsgCenter.class);
private static Core core = Core.getInstance();
/**
*
*
* @author https://github.com/yaphone
* @date 2017423 2:30:48
* @param msgList
* @return
*/
public static JSONArray produceMsg(JSONArray msgList) {
JSONArray result = new JSONArray();
for (int i = 0; i < msgList.size(); i++) {
JSONObject msg = new JSONObject();
JSONObject m = msgList.getJSONObject(i);
m.put("groupMsg", false);// 是否是群消息
if (m.getString("FromUserName").contains("@@") || m.getString("ToUserName").contains("@@")) { // 群聊消息
if (m.getString("FromUserName").contains("@@")
&& !core.getGroupIdList().contains(m.getString("FromUserName"))) {
core.getGroupIdList().add((m.getString("FromUserName")));
} else if (m.getString("ToUserName").contains("@@")
&& !core.getGroupIdList().contains(m.getString("ToUserName"))) {
core.getGroupIdList().add((m.getString("ToUserName")));
}
// 群消息与普通消息不同的是在其消息体Content中会包含发送者id及":<br/>"消息,这里需要处理一下,去掉多余信息,只保留消息内容
if (m.getString("Content").contains("<br/>")) {
String content = m.getString("Content").substring(m.getString("Content").indexOf("<br/>") + 5);
m.put("Content", content);
m.put("groupMsg", true);
}
} else {
CommonTools.msgFormatter(m, "Content");
}
if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_TEXT.getCode())) { // words
// 文本消息
if (m.getString("Url").length() != 0) {
String regEx = "(.+?\\(.+?\\))";
Matcher matcher = CommonTools.getMatcher(regEx, m.getString("Content"));
String data = "Map";
if (matcher.find()) {
data = matcher.group(1);
}
msg.put("Type", "Map");
msg.put("Text", data);
} else {
msg.put("Type", MsgTypeEnum.TEXT.getType());
msg.put("Text", m.getString("Content"));
}
m.put("Type", msg.getString("Type"));
m.put("Text", msg.getString("Text"));
} else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_IMAGE.getCode())
|| m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_EMOTICON.getCode())) { // 图片消息
m.put("Type", MsgTypeEnum.PIC.getType());
} else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_VOICE.getCode())) { // 语音消息
m.put("Type", MsgTypeEnum.VOICE.getType());
} else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_VERIFYMSG.getCode())) {// friends
// 好友确认消息
// MessageTools.addFriend(core, userName, 3, ticket); // 确认添加好友
m.put("Type", MsgTypeEnum.VERIFYMSG.getType());
} else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_SHARECARD.getCode())) { // 共享名片
m.put("Type", MsgTypeEnum.NAMECARD.getType());
} else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_VIDEO.getCode())
|| m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_MICROVIDEO.getCode())) {// viedo
m.put("Type", MsgTypeEnum.VIEDO.getType());
} else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_MEDIA.getCode())) { // 多媒体消息
m.put("Type", MsgTypeEnum.MEDIA.getType());
} else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_STATUSNOTIFY.getCode())) {// phone
// init
// 微信初始化消息
} else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_SYS.getCode())) {// 系统消息
m.put("Type", MsgTypeEnum.SYS.getType());
} else if (m.getInteger("MsgType").equals(MsgCodeEnum.MSGTYPE_RECALLED.getCode())) { // 撤回消息
} else {
LOG.info("Useless msg");
}
LOG.info("收到消息一条,来自: " + m.getString("FromUserName"));
result.add(m);
}
return result;
}
/**
*
*
* @author https://github.com/yaphone
* @date 2017514 10:52:34
* @param msgHandler
*/
public static void handleMsg(IMsgHandlerFace msgHandler) {
while (true) {
if (core.getMsgList().size() > 0 && core.getMsgList().get(0).getContent() != null) {
if (core.getMsgList().get(0).getContent().length() > 0) {
BaseMsg msg = core.getMsgList().get(0);
if (msg.getType() != null) {
try {
if (msg.getType().equals(MsgTypeEnum.TEXT.getType())) {
String result = msgHandler.textMsgHandle(msg);
MessageTools.sendMsgById(result, core.getMsgList().get(0).getFromUserName());
} else if (msg.getType().equals(MsgTypeEnum.PIC.getType())) {
String result = msgHandler.picMsgHandle(msg);
MessageTools.sendMsgById(result, core.getMsgList().get(0).getFromUserName());
} else if (msg.getType().equals(MsgTypeEnum.VOICE.getType())) {
String result = msgHandler.voiceMsgHandle(msg);
MessageTools.sendMsgById(result, core.getMsgList().get(0).getFromUserName());
} else if (msg.getType().equals(MsgTypeEnum.VIEDO.getType())) {
String result = msgHandler.viedoMsgHandle(msg);
MessageTools.sendMsgById(result, core.getMsgList().get(0).getFromUserName());
} else if (msg.getType().equals(MsgTypeEnum.NAMECARD.getType())) {
String result = msgHandler.nameCardMsgHandle(msg);
MessageTools.sendMsgById(result, core.getMsgList().get(0).getFromUserName());
} else if (msg.getType().equals(MsgTypeEnum.SYS.getType())) { // 系统消息
msgHandler.sysMsgHandle(msg);
} else if (msg.getType().equals(MsgTypeEnum.VERIFYMSG.getType())) { // 确认添加好友消息
String result = msgHandler.verifyAddFriendMsgHandle(msg);
MessageTools.sendMsgById(result,
core.getMsgList().get(0).getRecommendInfo().getUserName());
} else if (msg.getType().equals(MsgTypeEnum.MEDIA.getType())) { // 多媒体消息
String result = msgHandler.mediaMsgHandle(msg);
MessageTools.sendMsgById(result, core.getMsgList().get(0).getFromUserName());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
core.getMsgList().remove(0);
}
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

@ -0,0 +1,91 @@
package cn.zhouyafeng.itchat4j.face;
import cn.zhouyafeng.itchat4j.beans.BaseMsg;
/**
*
*
* @author https://github.com/yaphone
* @date 2017420 12:13:49
* @version 1.0
*
*/
public interface IMsgHandlerFace {
/**
*
* @author https://github.com/yaphone
* @date 2017420 12:15:00
* @param msg
* @return
*/
public String textMsgHandle(BaseMsg msg);
/**
*
*
* @author https://github.com/yaphone
* @date 2017421 11:07:06
* @param msg
* @return
*/
public String picMsgHandle(BaseMsg msg);
/**
*
*
* @author https://github.com/yaphone
* @date 2017422 12:09:44
* @param msg
* @return
*/
public String voiceMsgHandle(BaseMsg msg);
/**
*
*
* @author https://github.com/yaphone
* @date 2017423 12:19:50
* @param msg
* @return
*/
public String viedoMsgHandle(BaseMsg msg);
/**
*
*
* @author https://github.com/yaphone
* @date 201751 12:50:50
* @param msg
* @return
*/
public String nameCardMsgHandle(BaseMsg msg);
/**
*
*
* @author Relyn
* @date 201762117:43:51
* @param msg
* @return
*/
public void sysMsgHandle(BaseMsg msg);
/**
*
*
* @date 2017628 10:15:30
* @param msg
* @return
*/
public String verifyAddFriendMsgHandle(BaseMsg msg);
/**
*
*
* @date 2017721 11:59:14
* @param msg
* @return
*/
public String mediaMsgHandle(BaseMsg msg);
}

@ -0,0 +1,82 @@
package cn.zhouyafeng.itchat4j.service;
/**
*
*
* @author https://github.com/yaphone
* @date 2017513 12:07:21
* @version 1.0
*
*/
public interface ILoginService {
/**
*
*
* @author https://github.com/yaphone
* @date 2017513 12:14:07
* @return
*/
boolean login();
/**
* UUID
*
* @author https://github.com/yaphone
* @date 2017513 12:21:40
* @param qrPath
* @return
*/
String getUuid();
/**
*
*
* @author https://github.com/yaphone
* @date 2017513 12:13:51
* @param qrPath
* @return
*/
boolean getQR(String qrPath);
/**
* web
*
* @author https://github.com/yaphone
* @date 2017513 12:14:13
* @return
*/
boolean webWxInit();
/**
*
*
* @author https://github.com/yaphone
* @date 2017513 12:14:24
*/
void wxStatusNotify();
/**
*
*
* @author https://github.com/yaphone
* @date 2017513 12:14:37
*/
void startReceiving();
/**
*
*
* @author https://github.com/yaphone
* @date 2017513 2:26:18
*/
void webWxGetContact();
/**
*
*
* @date 2017622 11:24:35
*/
void WebWxBatchGetContact();
}

@ -0,0 +1,688 @@
package cn.zhouyafeng.itchat4j.service.impl;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.regex.Matcher;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import cn.zhouyafeng.itchat4j.beans.BaseMsg;
import cn.zhouyafeng.itchat4j.core.Core;
import cn.zhouyafeng.itchat4j.core.MsgCenter;
import cn.zhouyafeng.itchat4j.service.ILoginService;
import cn.zhouyafeng.itchat4j.utils.Config;
import cn.zhouyafeng.itchat4j.utils.MyHttpClient;
import cn.zhouyafeng.itchat4j.utils.SleepUtils;
import cn.zhouyafeng.itchat4j.utils.enums.ResultEnum;
import cn.zhouyafeng.itchat4j.utils.enums.RetCodeEnum;
import cn.zhouyafeng.itchat4j.utils.enums.StorageLoginInfoEnum;
import cn.zhouyafeng.itchat4j.utils.enums.URLEnum;
import cn.zhouyafeng.itchat4j.utils.enums.parameters.BaseParaEnum;
import cn.zhouyafeng.itchat4j.utils.enums.parameters.LoginParaEnum;
import cn.zhouyafeng.itchat4j.utils.enums.parameters.StatusNotifyParaEnum;
import cn.zhouyafeng.itchat4j.utils.enums.parameters.UUIDParaEnum;
import cn.zhouyafeng.itchat4j.utils.tools.CommonTools;
/**
*
*
* @author https://github.com/yaphone
* @date 2017513 12:09:35
* @version 1.0
*
*/
public class LoginServiceImpl implements ILoginService {
private static Logger LOG = LoggerFactory.getLogger(LoginServiceImpl.class);
private Core core = Core.getInstance();
private MyHttpClient httpClient = core.getMyHttpClient();
private MyHttpClient myHttpClient = core.getMyHttpClient();
public LoginServiceImpl() {
}
@Override
public boolean login() {
boolean isLogin = false;
// 组装参数和URL
List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
params.add(new BasicNameValuePair(LoginParaEnum.LOGIN_ICON.para(), LoginParaEnum.LOGIN_ICON.value()));
params.add(new BasicNameValuePair(LoginParaEnum.UUID.para(), core.getUuid()));
params.add(new BasicNameValuePair(LoginParaEnum.TIP.para(), LoginParaEnum.TIP.value()));
// long time = 4000;
while (!isLogin) {
// SleepUtils.sleep(time += 1000);
long millis = System.currentTimeMillis();
params.add(new BasicNameValuePair(LoginParaEnum.R.para(), String.valueOf(millis / 1579L)));
params.add(new BasicNameValuePair(LoginParaEnum._.para(), String.valueOf(millis)));
HttpEntity entity = httpClient.doGet(URLEnum.LOGIN_URL.getUrl(), params, true, null);
try {
String result = EntityUtils.toString(entity);
String status = checklogin(result);
if (ResultEnum.SUCCESS.getCode().equals(status)) {
processLoginInfo(result); // 处理结果
isLogin = true;
core.setAlive(isLogin);
break;
}
if (ResultEnum.WAIT_CONFIRM.getCode().equals(status)) {
LOG.info("请点击微信确认按钮,进行登陆");
}
} catch (Exception e) {
LOG.error("微信登陆异常!", e);
}
}
return isLogin;
}
@Override
public String getUuid() {
// 组装参数和URL
List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
params.add(new BasicNameValuePair(UUIDParaEnum.APP_ID.para(), UUIDParaEnum.APP_ID.value()));
params.add(new BasicNameValuePair(UUIDParaEnum.FUN.para(), UUIDParaEnum.FUN.value()));
params.add(new BasicNameValuePair(UUIDParaEnum.LANG.para(), UUIDParaEnum.LANG.value()));
params.add(new BasicNameValuePair(UUIDParaEnum._.para(), String.valueOf(System.currentTimeMillis())));
HttpEntity entity = httpClient.doGet(URLEnum.UUID_URL.getUrl(), params, true, null);
try {
String result = EntityUtils.toString(entity);
String regEx = "window.QRLogin.code = (\\d+); window.QRLogin.uuid = \"(\\S+?)\";";
Matcher matcher = CommonTools.getMatcher(regEx, result);
if (matcher.find()) {
if ((ResultEnum.SUCCESS.getCode().equals(matcher.group(1)))) {
core.setUuid(matcher.group(2));
}
}
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
return core.getUuid();
}
@Override
public boolean getQR(String qrPath) {
qrPath = qrPath + File.separator + "QR.jpg";
String qrUrl = URLEnum.QRCODE_URL.getUrl() + core.getUuid();
HttpEntity entity = myHttpClient.doGet(qrUrl, null, true, null);
try {
OutputStream out = new FileOutputStream(qrPath);
byte[] bytes = EntityUtils.toByteArray(entity);
out.write(bytes);
out.flush();
out.close();
try {
CommonTools.printQr(qrPath); // 打开登陆二维码图片
} catch (Exception e) {
LOG.info(e.getMessage());
}
} catch (Exception e) {
LOG.info(e.getMessage());
return false;
}
return true;
}
@Override
public boolean webWxInit() {
core.setAlive(true);
core.setLastNormalRetcodeTime(System.currentTimeMillis());
// 组装请求URL和参数
String url = String.format(URLEnum.INIT_URL.getUrl(),
core.getLoginInfo().get(StorageLoginInfoEnum.url.getKey()),
String.valueOf(System.currentTimeMillis() / 3158L),
core.getLoginInfo().get(StorageLoginInfoEnum.pass_ticket.getKey()));
Map<String, Object> paramMap = core.getParamMap();
// 请求初始化接口
HttpEntity entity = httpClient.doPost(url, JSON.toJSONString(paramMap));
try {
String result = EntityUtils.toString(entity, Consts.UTF_8);
JSONObject obj = JSON.parseObject(result);
JSONObject user = obj.getJSONObject(StorageLoginInfoEnum.User.getKey());
JSONObject syncKey = obj.getJSONObject(StorageLoginInfoEnum.SyncKey.getKey());
core.getLoginInfo().put(StorageLoginInfoEnum.InviteStartCount.getKey(),
obj.getInteger(StorageLoginInfoEnum.InviteStartCount.getKey()));
core.getLoginInfo().put(StorageLoginInfoEnum.SyncKey.getKey(), syncKey);
JSONArray syncArray = syncKey.getJSONArray("List");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < syncArray.size(); i++) {
sb.append(syncArray.getJSONObject(i).getString("Key") + "_"
+ syncArray.getJSONObject(i).getString("Val") + "|");
}
// 1_661706053|2_661706420|3_661706415|1000_1494151022|
String synckey = sb.toString();
// 1_661706053|2_661706420|3_661706415|1000_1494151022
core.getLoginInfo().put(StorageLoginInfoEnum.synckey.getKey(), synckey.substring(0, synckey.length() - 1));// 1_656161336|2_656161626|3_656161313|11_656159955|13_656120033|201_1492273724|1000_1492265953|1001_1492250432|1004_1491805192
core.setUserName(user.getString("UserName"));
core.setNickName(user.getString("NickName"));
core.setUserSelf(obj.getJSONObject("User"));
String chatSet = obj.getString("ChatSet");
String[] chatSetArray = chatSet.split(",");
for (int i = 0; i < chatSetArray.length; i++) {
if (chatSetArray[i].indexOf("@@") != -1) {
// 更新GroupIdList
core.getGroupIdList().add(chatSetArray[i]); //
}
}
// JSONArray contactListArray = obj.getJSONArray("ContactList");
// for (int i = 0; i < contactListArray.size(); i++) {
// JSONObject o = contactListArray.getJSONObject(i);
// if (o.getString("UserName").indexOf("@@") != -1) {
// core.getGroupIdList().add(o.getString("UserName")); //
// // 更新GroupIdList
// core.getGroupList().add(o); // 更新GroupList
// core.getGroupNickNameList().add(o.getString("NickName"));
// }
// }
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
@Override
public void wxStatusNotify() {
// 组装请求URL和参数
String url = String.format(URLEnum.STATUS_NOTIFY_URL.getUrl(),
core.getLoginInfo().get(StorageLoginInfoEnum.pass_ticket.getKey()));
Map<String, Object> paramMap = core.getParamMap();
paramMap.put(StatusNotifyParaEnum.CODE.para(), StatusNotifyParaEnum.CODE.value());
paramMap.put(StatusNotifyParaEnum.FROM_USERNAME.para(), core.getUserName());
paramMap.put(StatusNotifyParaEnum.TO_USERNAME.para(), core.getUserName());
paramMap.put(StatusNotifyParaEnum.CLIENT_MSG_ID.para(), System.currentTimeMillis());
String paramStr = JSON.toJSONString(paramMap);
try {
HttpEntity entity = httpClient.doPost(url, paramStr);
EntityUtils.toString(entity, Consts.UTF_8);
} catch (Exception e) {
LOG.error("微信状态通知接口失败!", e);
}
}
@Override
public void startReceiving() {
core.setAlive(true);
new Thread(new Runnable() {
int retryCount = 0;
@Override
public void run() {
while (core.isAlive()) {
try {
Map<String, String> resultMap = syncCheck();
LOG.info(JSONObject.toJSONString(resultMap));
String retcode = resultMap.get("retcode");
String selector = resultMap.get("selector");
if (retcode.equals(RetCodeEnum.UNKOWN.getCode())) {
LOG.info(RetCodeEnum.UNKOWN.getType());
continue;
} else if (retcode.equals(RetCodeEnum.LOGIN_OUT.getCode())) { // 退出
LOG.info(RetCodeEnum.LOGIN_OUT.getType());
break;
} else if (retcode.equals(RetCodeEnum.LOGIN_OTHERWHERE.getCode())) { // 其它地方登陆
LOG.info(RetCodeEnum.LOGIN_OTHERWHERE.getType());
break;
} else if (retcode.equals(RetCodeEnum.MOBILE_LOGIN_OUT.getCode())) { // 移动端退出
LOG.info(RetCodeEnum.MOBILE_LOGIN_OUT.getType());
break;
} else if (retcode.equals(RetCodeEnum.NORMAL.getCode())) {
core.setLastNormalRetcodeTime(System.currentTimeMillis()); // 最后收到正常报文时间
JSONObject msgObj = webWxSync();
if (selector.equals("2")) {
if (msgObj != null) {
try {
JSONArray msgList = new JSONArray();
msgList = msgObj.getJSONArray("AddMsgList");
msgList = MsgCenter.produceMsg(msgList);
for (int j = 0; j < msgList.size(); j++) {
BaseMsg baseMsg = JSON.toJavaObject(msgList.getJSONObject(j),
BaseMsg.class);
core.getMsgList().add(baseMsg);
}
} catch (Exception e) {
LOG.info(e.getMessage());
}
}
} else if (selector.equals("7")) {
webWxSync();
} else if (selector.equals("4")) {
continue;
} else if (selector.equals("3")) {
continue;
} else if (selector.equals("6")) {
if (msgObj != null) {
try {
JSONArray msgList = new JSONArray();
msgList = msgObj.getJSONArray("AddMsgList");
JSONArray modContactList = msgObj.getJSONArray("ModContactList"); // 存在删除或者新增的好友信息
msgList = MsgCenter.produceMsg(msgList);
for (int j = 0; j < msgList.size(); j++) {
JSONObject userInfo = modContactList.getJSONObject(j);
// 存在主动加好友之后的同步联系人到本地
core.getContactList().add(userInfo);
}
} catch (Exception e) {
LOG.info(e.getMessage());
}
}
}
} else {
JSONObject obj = webWxSync();
}
} catch (Exception e) {
LOG.info(e.getMessage());
retryCount += 1;
if (core.getReceivingRetryCount() < retryCount) {
core.setAlive(false);
} else {
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
LOG.info(e.getMessage());
}
}
}
}
}
}).start();
}
@Override
public void webWxGetContact() {
String url = String.format(URLEnum.WEB_WX_GET_CONTACT.getUrl(),
core.getLoginInfo().get(StorageLoginInfoEnum.url.getKey()));
Map<String, Object> paramMap = core.getParamMap();
HttpEntity entity = httpClient.doPost(url, JSON.toJSONString(paramMap));
try {
String result = EntityUtils.toString(entity, Consts.UTF_8);
JSONObject fullFriendsJsonList = JSON.parseObject(result);
// 查看seq是否为00表示好友列表已全部获取完毕若大于0则表示好友列表未获取完毕当前的字节数断点续传
long seq = 0;
long currentTime = 0L;
List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
if (fullFriendsJsonList.get("Seq") != null) {
seq = fullFriendsJsonList.getLong("Seq");
currentTime = new Date().getTime();
}
core.setMemberCount(fullFriendsJsonList.getInteger(StorageLoginInfoEnum.MemberCount.getKey()));
JSONArray member = fullFriendsJsonList.getJSONArray(StorageLoginInfoEnum.MemberList.getKey());
// 循环获取seq直到为0即获取全部好友列表 ==0好友获取完毕 >0好友未获取完毕此时seq为已获取的字节数
while (seq > 0) {
// 设置seq传参
params.add(new BasicNameValuePair("r", String.valueOf(currentTime)));
params.add(new BasicNameValuePair("seq", String.valueOf(seq)));
entity = httpClient.doGet(url, params, false, null);
params.remove(new BasicNameValuePair("r", String.valueOf(currentTime)));
params.remove(new BasicNameValuePair("seq", String.valueOf(seq)));
result = EntityUtils.toString(entity, Consts.UTF_8);
fullFriendsJsonList = JSON.parseObject(result);
if (fullFriendsJsonList.get("Seq") != null) {
seq = fullFriendsJsonList.getLong("Seq");
currentTime = new Date().getTime();
}
// 累加好友列表
member.addAll(fullFriendsJsonList.getJSONArray(StorageLoginInfoEnum.MemberList.getKey()));
}
core.setMemberCount(member.size());
for (Iterator<?> iterator = member.iterator(); iterator.hasNext();) {
JSONObject o = (JSONObject) iterator.next();
if ((o.getInteger("VerifyFlag") & 8) != 0) { // 公众号/服务号
core.getPublicUsersList().add(o);
} else if (Config.API_SPECIAL_USER.contains(o.getString("UserName"))) { // 特殊账号
core.getSpecialUsersList().add(o);
} else if (o.getString("UserName").indexOf("@@") != -1) { // 群聊
if (!core.getGroupIdList().contains(o.getString("UserName"))) {
core.getGroupNickNameList().add(o.getString("NickName"));
core.getGroupIdList().add(o.getString("UserName"));
core.getGroupList().add(o);
}
} else if (o.getString("UserName").equals(core.getUserSelf().getString("UserName"))) { // 自己
core.getContactList().remove(o);
} else { // 普通联系人
core.getContactList().add(o);
}
}
return;
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
return;
}
@Override
public void WebWxBatchGetContact() {
String url = String.format(URLEnum.WEB_WX_BATCH_GET_CONTACT.getUrl(),
core.getLoginInfo().get(StorageLoginInfoEnum.url.getKey()), new Date().getTime(),
core.getLoginInfo().get(StorageLoginInfoEnum.pass_ticket.getKey()));
Map<String, Object> paramMap = core.getParamMap();
paramMap.put("Count", core.getGroupIdList().size());
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
for (int i = 0; i < core.getGroupIdList().size(); i++) {
HashMap<String, String> map = new HashMap<String, String>();
map.put("UserName", core.getGroupIdList().get(i));
map.put("EncryChatRoomId", "");
list.add(map);
}
paramMap.put("List", list);
HttpEntity entity = httpClient.doPost(url, JSON.toJSONString(paramMap));
try {
String text = EntityUtils.toString(entity, Consts.UTF_8);
JSONObject obj = JSON.parseObject(text);
JSONArray contactList = obj.getJSONArray("ContactList");
for (int i = 0; i < contactList.size(); i++) { // 群好友
if (contactList.getJSONObject(i).getString("UserName").indexOf("@@") > -1) { // 群
core.getGroupNickNameList().add(contactList.getJSONObject(i).getString("NickName")); // 更新群昵称列表
core.getGroupList().add(contactList.getJSONObject(i)); // 更新群信息(所有)列表
core.getGroupMemeberMap().put(contactList.getJSONObject(i).getString("UserName"),
contactList.getJSONObject(i).getJSONArray("MemberList")); // 更新群成员Map
}
}
} catch (Exception e) {
LOG.info(e.getMessage());
}
}
/**
*
*
* @param result
* @return
*/
public String checklogin(String result) {
String regEx = "window.code=(\\d+)";
Matcher matcher = CommonTools.getMatcher(regEx, result);
if (matcher.find()) {
return matcher.group(1);
}
return null;
}
/**
*
*
* @author https://github.com/yaphone
* @date 201749 12:16:26
* @param result
*/
private void processLoginInfo(String loginContent) {
String regEx = "window.redirect_uri=\"(\\S+)\";";
Matcher matcher = CommonTools.getMatcher(regEx, loginContent);
if (matcher.find()) {
String originalUrl = matcher.group(1);
String url = originalUrl.substring(0, originalUrl.lastIndexOf('/')); // https://wx2.qq.com/cgi-bin/mmwebwx-bin
core.getLoginInfo().put("url", url);
Map<String, List<String>> possibleUrlMap = this.getPossibleUrlMap();
Iterator<Entry<String, List<String>>> iterator = possibleUrlMap.entrySet().iterator();
Entry<String, List<String>> entry;
String fileUrl;
String syncUrl;
while (iterator.hasNext()) {
entry = iterator.next();
String indexUrl = entry.getKey();
fileUrl = "https://" + entry.getValue().get(0) + "/cgi-bin/mmwebwx-bin";
syncUrl = "https://" + entry.getValue().get(1) + "/cgi-bin/mmwebwx-bin";
if (core.getLoginInfo().get("url").toString().contains(indexUrl)) {
core.setIndexUrl(indexUrl);
core.getLoginInfo().put("fileUrl", fileUrl);
core.getLoginInfo().put("syncUrl", syncUrl);
break;
}
}
if (core.getLoginInfo().get("fileUrl") == null && core.getLoginInfo().get("syncUrl") == null) {
core.getLoginInfo().put("fileUrl", url);
core.getLoginInfo().put("syncUrl", url);
}
core.getLoginInfo().put("deviceid", "e" + String.valueOf(new Random().nextLong()).substring(1, 16)); // 生成15位随机数
core.getLoginInfo().put("BaseRequest", new ArrayList<String>());
String text = "";
try {
Map<String, String> header = new HashMap<>();
header.put("client-version","2.0.0");
header.put("extspam","Go8FCIkFEokFCggwMDAwMDAwMRAGGvAESySibk50w5Wb3uTl2c2h64jVVrV7gNs06GFlWplHQbY/5FfiO++1yH4ykCyNPWKXmco+wfQzK5R98D3so7rJ5LmGFvBLjGceleySrc3SOf2Pc1gVehzJgODeS0lDL3/I/0S2SSE98YgKleq6Uqx6ndTy9yaL9qFxJL7eiA/R3SEfTaW1SBoSITIu+EEkXff+Pv8NHOk7N57rcGk1w0ZzRrQDkXTOXFN2iHYIzAAZPIOY45Lsh+A4slpgnDiaOvRtlQYCt97nmPLuTipOJ8Qc5pM7ZsOsAPPrCQL7nK0I7aPrFDF0q4ziUUKettzW8MrAaiVfmbD1/VkmLNVqqZVvBCtRblXb5FHmtS8FxnqCzYP4WFvz3T0TcrOqwLX1M/DQvcHaGGw0B0y4bZMs7lVScGBFxMj3vbFi2SRKbKhaitxHfYHAOAa0X7/MSS0RNAjdwoyGHeOepXOKY+h3iHeqCvgOH6LOifdHf/1aaZNwSkGotYnYScW8Yx63LnSwba7+hESrtPa/huRmB9KWvMCKbDThL/nne14hnL277EDCSocPu3rOSYjuB9gKSOdVmWsj9Dxb/iZIe+S6AiG29Esm+/eUacSba0k8wn5HhHg9d4tIcixrxveflc8vi2/wNQGVFNsGO6tB5WF0xf/plngOvQ1/ivGV/C1Qpdhzznh0ExAVJ6dwzNg7qIEBaw+BzTJTUuRcPk92Sn6QDn2Pu3mpONaEumacjW4w6ipPnPw+g2TfywJjeEcpSZaP4Q3YV5HG8D6UjWA4GSkBKculWpdCMadx0usMomsSS/74QgpYqcPkmamB4nVv1JxczYITIqItIKjD35IGKAUwAA==");
originalUrl = originalUrl +"&fun=new&version=v2&mod=desktop&lang=zh_CN";
HttpEntity entity = myHttpClient.doGet(originalUrl, null, false, header);
text = EntityUtils.toString(entity);
} catch (Exception e) {
LOG.info(e.getMessage());
return;
}
//add by 默非默 2017-08-01 22:28:09
//如果登录被禁止时则登录返回的message内容不为空下面代码则判断登录内容是否为空不为空则退出程序
String msg = getLoginMessage(text);
if (!"".equals(msg)){
LOG.info(msg);
System.exit(0);
}
Document doc = CommonTools.xmlParser(text);
if (doc != null) {
core.getLoginInfo().put(StorageLoginInfoEnum.skey.getKey(),
doc.getElementsByTagName(StorageLoginInfoEnum.skey.getKey()).item(0).getFirstChild()
.getNodeValue());
core.getLoginInfo().put(StorageLoginInfoEnum.wxsid.getKey(),
doc.getElementsByTagName(StorageLoginInfoEnum.wxsid.getKey()).item(0).getFirstChild()
.getNodeValue());
core.getLoginInfo().put(StorageLoginInfoEnum.wxuin.getKey(),
doc.getElementsByTagName(StorageLoginInfoEnum.wxuin.getKey()).item(0).getFirstChild()
.getNodeValue());
core.getLoginInfo().put(StorageLoginInfoEnum.pass_ticket.getKey(),
doc.getElementsByTagName(StorageLoginInfoEnum.pass_ticket.getKey()).item(0).getFirstChild()
.getNodeValue());
}
}
}
private Map<String, List<String>> getPossibleUrlMap() {
Map<String, List<String>> possibleUrlMap = new HashMap<String, List<String>>();
possibleUrlMap.put("wx.qq.com", new ArrayList<String>() {
/**
*
*/
private static final long serialVersionUID = 1L;
{
add("file.wx.qq.com");
add("webpush.wx.qq.com");
}
});
possibleUrlMap.put("wx2.qq.com", new ArrayList<String>() {
/**
*
*/
private static final long serialVersionUID = 1L;
{
add("file.wx2.qq.com");
add("webpush.wx2.qq.com");
}
});
possibleUrlMap.put("wx8.qq.com", new ArrayList<String>() {
/**
*
*/
private static final long serialVersionUID = 1L;
{
add("file.wx8.qq.com");
add("webpush.wx8.qq.com");
}
});
possibleUrlMap.put("web2.wechat.com", new ArrayList<String>() {
/**
*
*/
private static final long serialVersionUID = 1L;
{
add("file.web2.wechat.com");
add("webpush.web2.wechat.com");
}
});
possibleUrlMap.put("wechat.com", new ArrayList<String>() {
/**
*
*/
private static final long serialVersionUID = 1L;
{
add("file.web.wechat.com");
add("webpush.web.wechat.com");
}
});
return possibleUrlMap;
}
/**
* sync the messages
*
* @author https://github.com/yaphone
* @date 2017512 12:24:55
* @return
*/
private JSONObject webWxSync() {
JSONObject result = null;
String url = String.format(URLEnum.WEB_WX_SYNC_URL.getUrl(),
core.getLoginInfo().get(StorageLoginInfoEnum.url.getKey()),
core.getLoginInfo().get(StorageLoginInfoEnum.wxsid.getKey()),
core.getLoginInfo().get(StorageLoginInfoEnum.skey.getKey()),
core.getLoginInfo().get(StorageLoginInfoEnum.pass_ticket.getKey()));
Map<String, Object> paramMap = core.getParamMap();
paramMap.put(StorageLoginInfoEnum.SyncKey.getKey(),
core.getLoginInfo().get(StorageLoginInfoEnum.SyncKey.getKey()));
paramMap.put("rr", -new Date().getTime() / 1000);
String paramStr = JSON.toJSONString(paramMap);
try {
HttpEntity entity = myHttpClient.doPost(url, paramStr);
String text = EntityUtils.toString(entity, Consts.UTF_8);
JSONObject obj = JSON.parseObject(text);
if (obj.getJSONObject("BaseResponse").getInteger("Ret") != 0) {
result = null;
} else {
result = obj;
core.getLoginInfo().put(StorageLoginInfoEnum.SyncKey.getKey(), obj.getJSONObject("SyncCheckKey"));
JSONArray syncArray = obj.getJSONObject(StorageLoginInfoEnum.SyncKey.getKey()).getJSONArray("List");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < syncArray.size(); i++) {
sb.append(syncArray.getJSONObject(i).getString("Key") + "_"
+ syncArray.getJSONObject(i).getString("Val") + "|");
}
String synckey = sb.toString();
core.getLoginInfo().put(StorageLoginInfoEnum.synckey.getKey(),
synckey.substring(0, synckey.length() - 1));// 1_656161336|2_656161626|3_656161313|11_656159955|13_656120033|201_1492273724|1000_1492265953|1001_1492250432|1004_1491805192
}
} catch (Exception e) {
LOG.info(e.getMessage());
}
return result;
}
/**
* check whether there's a message
*
* @author https://github.com/yaphone
* @date 2017416 11:11:34
* @return
*
*/
private Map<String, String> syncCheck() {
Map<String, String> resultMap = new HashMap<String, String>();
// 组装请求URL和参数
String url = core.getLoginInfo().get(StorageLoginInfoEnum.syncUrl.getKey()) + URLEnum.SYNC_CHECK_URL.getUrl();
List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
for (BaseParaEnum baseRequest : BaseParaEnum.values()) {
params.add(new BasicNameValuePair(baseRequest.para().toLowerCase(),
core.getLoginInfo().get(baseRequest.value()).toString()));
}
params.add(new BasicNameValuePair("r", String.valueOf(new Date().getTime())));
params.add(new BasicNameValuePair("synckey", (String) core.getLoginInfo().get("synckey")));
params.add(new BasicNameValuePair("_", String.valueOf(new Date().getTime())));
SleepUtils.sleep(7);
try {
HttpEntity entity = myHttpClient.doGet(url, params, true, null);
if (entity == null) {
resultMap.put("retcode", "9999");
resultMap.put("selector", "9999");
return resultMap;
}
String text = EntityUtils.toString(entity);
String regEx = "window.synccheck=\\{retcode:\"(\\d+)\",selector:\"(\\d+)\"\\}";
Matcher matcher = CommonTools.getMatcher(regEx, text);
if (!matcher.find() || matcher.group(1).equals("2")) {
LOG.info(String.format("Unexpected sync check result: %s", text));
} else {
resultMap.put("retcode", matcher.group(1));
resultMap.put("selector", matcher.group(2));
}
} catch (Exception e) {
e.printStackTrace();
}
return resultMap;
}
/**
* message
* @param result
* @return
*/
public String getLoginMessage(String result){
String[] strArr = result.split("<message>");
String[] rs = strArr[1].split("</message>");
if (rs!=null && rs.length>1) {
return rs[0];
}
return "";
}
}

@ -0,0 +1,38 @@
package cn.zhouyafeng.itchat4j.thread;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cn.zhouyafeng.itchat4j.core.Core;
import cn.zhouyafeng.itchat4j.utils.SleepUtils;
/**
* 线
* <p>
*
* LoginServiceImpl.syncCheck()线retcode"0"25
* 线60线
* </p>
*
* @author https://github.com/yaphone
* @date 2017517 10:53:15
* @version 1.0
*
*/
public class CheckLoginStatusThread implements Runnable {
private static Logger LOG = LoggerFactory.getLogger(CheckLoginStatusThread.class);
private Core core = Core.getInstance();
@Override
public void run() {
while (core.isAlive()) {
long t1 = System.currentTimeMillis(); // 秒为单位
if (t1 - core.getLastNormalRetcodeTime() > 60 * 1000) { // 超过60秒判为离线
core.setAlive(false);
LOG.info("微信已离线");
}
SleepUtils.sleep(10 * 1000); // 休眠10秒
}
}
}

@ -0,0 +1,74 @@
package cn.zhouyafeng.itchat4j.utils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import cn.zhouyafeng.itchat4j.utils.enums.OsNameEnum;
/**
*
*
* @author https://github.com/yaphone
* @date 2017423 2:26:21
* @version 1.0
*
*/
public class Config {
public static final String API_WXAPPID = "API_WXAPPID";
public static final String picDir = "D://itchat4j";
public static final String VERSION = "1.2.18";
public static final String BASE_URL = "https://login.weixin.qq.com";
public static final String OS = "";
public static final String DIR = "";
public static final String DEFAULT_QR = "QR.jpg";
public static final String USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36";
public static final ArrayList<String> API_SPECIAL_USER = new ArrayList<String>(Arrays.asList("filehelper", "weibo",
"qqmail", "fmessage", "tmessage", "qmessage", "qqsync", "floatbottle", "lbsapp", "shakeapp", "medianote",
"qqfriend", "readerapp", "blogapp", "facebookapp", "masssendapp", "meishiapp", "feedsapp", "voip",
"blogappweixin", "brandsessionholder", "weixin", "weixinreminder", "officialaccounts", "wxitil",
"notification_messages", "wxid_novlwrv3lqwv11", "gh_22b87fa7cb3c", "userexperience_alarm"));
/**
*
*
* @author https://github.com/yaphone
* @date 201748 10:27:42
* @return
*/
public static String getLocalPath() {
String localPath = null;
try {
localPath = new File("").getCanonicalPath();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return localPath;
}
/**
*
*
* @author https://github.com/yaphone
* @date 201748 10:27:53
*/
public static OsNameEnum getOsNameEnum() {
String os = System.getProperty("os.name").toUpperCase();
if (os.indexOf(OsNameEnum.DARWIN.toString()) >= 0) {
return OsNameEnum.DARWIN;
} else if (os.indexOf(OsNameEnum.WINDOWS.toString()) >= 0) {
return OsNameEnum.WINDOWS;
} else if (os.indexOf(OsNameEnum.LINUX.toString()) >= 0) {
return OsNameEnum.LINUX;
} else if (os.indexOf(OsNameEnum.MAC.toString()) >= 0) {
return OsNameEnum.MAC;
}
return OsNameEnum.OTHER;
}
}

@ -0,0 +1,34 @@
package cn.zhouyafeng.itchat4j.utils;
/**
*
*
* @author https=//github.com/yaphone
* @date 201755 11=29=04
* @version 1.0
*
*/
public class ConstantConfigEnum {
public static final int APPMSGTYPE_TEXT = 1;
public static final int APPMSGTYPE_IMG = 2;
public static final int APPMSGTYPE_AUDIO = 3;
public static final int APPMSGTYPE_VIDEO = 4;
public static final int APPMSGTYPE_URL = 5;
public static final int APPMSGTYPE_ATTACH = 6;
public static final int APPMSGTYPE_OPEN = 7;
public static final int APPMSGTYPE_EMOJI = 8;
public static final int APPMSGTYPE_VOICE_REMIND = 9;
public static final int APPMSGTYPE_SCAN_GOOD = 10;
public static final int APPMSGTYPE_GOOD = 13;
public static final int APPMSGTYPE_EMOTION = 15;
public static final int APPMSGTYPE_CARD_TICKET = 16;
public static final int APPMSGTYPE_REALTIME_SHARE_LOCATION = 17;
// public static final int APPMSGTYPE_TRANSFERS = 2e3;
public static final int APPMSGTYPE_RED_ENVELOPES = 2001;
public static final int APPMSGTYPE_READER_TYPE = 100001;
public static final int UPLOAD_MEDIA_TYPE_IMAGE = 1;
public static final int UPLOAD_MEDIA_TYPE_VIDEO = 2;
public static final int UPLOAD_MEDIA_TYPE_AUDIO = 3;
public static final int UPLOAD_MEDIA_TYPE_ATTACHMENT = 4;
}

@ -0,0 +1,6 @@
package cn.zhouyafeng.itchat4j.utils;
public class MsgKeywords {
public static String newFriendStr = "我通过了你的朋友验证请求";
}

@ -0,0 +1,183 @@
package cn.zhouyafeng.itchat4j.utils;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Logger;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.RequestConfig;
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.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
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;
/**
* HTTP访Apache HttpClient
*
* @author https://github.com/yaphone
* @date 201749 7:05:04
* @version 1.0
*
*/
public class MyHttpClient {
private Logger logger = Logger.getLogger("MyHttpClient");
private static CloseableHttpClient httpClient = HttpClients.createDefault();
private static MyHttpClient instance = null;
private static CookieStore cookieStore;
static {
cookieStore = new BasicCookieStore();
// 将CookieStore设置到httpClient中
httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
}
public static String getCookie(String name) {
List<Cookie> cookies = cookieStore.getCookies();
for (Cookie cookie : cookies) {
if (cookie.getName().equalsIgnoreCase(name)) {
return cookie.getValue();
}
}
return null;
}
private MyHttpClient() {
}
/**
* cookies
*
* @author https://github.com/yaphone
* @date 201757 8:37:17
* @return
*/
public static MyHttpClient getInstance() {
if (instance == null) {
synchronized (MyHttpClient.class) {
if (instance == null) {
instance = new MyHttpClient();
}
}
}
return instance;
}
/**
* GET
*
* @author https://github.com/yaphone
* @date 201749 7:06:19
* @param url
* @param params
* @return
*/
public HttpEntity doGet(String url, List<BasicNameValuePair> params, boolean redirect,
Map<String, String> headerMap) {
HttpEntity entity = null;
HttpGet httpGet = new HttpGet();
try {
if (params != null) {
String paramStr = EntityUtils.toString(new UrlEncodedFormEntity(params, Consts.UTF_8));
httpGet = new HttpGet(url + "?" + paramStr);
} else {
httpGet = new HttpGet(url);
}
if (!redirect) {
httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build()); // 禁止重定向
}
httpGet.setHeader("User-Agent", Config.USER_AGENT);
if (headerMap != null) {
Set<Entry<String, String>> entries = headerMap.entrySet();
for (Entry<String, String> entry : entries) {
httpGet.setHeader(entry.getKey(), entry.getValue());
}
}
CloseableHttpResponse response = httpClient.execute(httpGet);
entity = response.getEntity();
} catch (ClientProtocolException e) {
logger.info(e.getMessage());
} catch (IOException e) {
logger.info(e.getMessage());
}
return entity;
}
/**
* POST
*
* @author https://github.com/yaphone
* @date 201749 7:06:35
* @param url
* @param params
* @return
*/
public HttpEntity doPost(String url, String paramsStr) {
HttpEntity entity = null;
HttpPost httpPost = new HttpPost();
try {
StringEntity params = new StringEntity(paramsStr, Consts.UTF_8);
httpPost = new HttpPost(url);
httpPost.setEntity(params);
httpPost.setHeader("Content-type", "application/json; charset=utf-8");
httpPost.setHeader("User-Agent", Config.USER_AGENT);
CloseableHttpResponse response = httpClient.execute(httpPost);
entity = response.getEntity();
} catch (ClientProtocolException e) {
logger.info(e.getMessage());
} catch (IOException e) {
logger.info(e.getMessage());
}
return entity;
}
/**
*
*
* @author https://github.com/yaphone
* @date 201757 9:19:23
* @param url
* @param reqEntity
* @return
*/
public HttpEntity doPostFile(String url, HttpEntity reqEntity) {
HttpEntity entity = null;
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("User-Agent", Config.USER_AGENT);
httpPost.setEntity(reqEntity);
try {
CloseableHttpResponse response = httpClient.execute(httpPost);
entity = response.getEntity();
} catch (Exception e) {
logger.info(e.getMessage());
}
return entity;
}
public static CloseableHttpClient getHttpClient() {
return httpClient;
}
}

@ -0,0 +1,20 @@
package cn.zhouyafeng.itchat4j.utils;
/**
* Created by xiaoxiaomo on 2017/5/6.
*/
public class SleepUtils {
/**
*
* @param time
*/
public static void sleep( long time ){
try {
Thread.sleep( time );
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

@ -0,0 +1,68 @@
package cn.zhouyafeng.itchat4j.utils.enums;
/**
*
*
* @author https://github.com/yaphone
* @date 2017423 12:15:00
* @version 1.0
*
*/
public enum MsgCodeEnum {
// public static final int MSGTYPE_TEXT = 1; // 文本消息类型
// public static final int MSGTYPE_IMAGE = 3; // 图片消息
// public static final int MSGTYPE_VOICE = 34; // 语音消息
// public static final int MSGTYPE_VIDEO = 43; // 小视频消息
// public static final int MSGTYPE_MICROVIDEO = 62; // 短视频消息
// public static final int MSGTYPE_EMOTICON = 47; // 表情消息
// public static final int MSGTYPE_APP = 49;
// public static final int MSGTYPE_VOIPMSG = 50;
// public static final int MSGTYPE_VOIPNOTIFY = 52;
// public static final int MSGTYPE_VOIPINVITE = 53;
// public static final int MSGTYPE_LOCATION = 48;
// public static final int MSGTYPE_STATUSNOTIFY = 51;
// public static final int MSGTYPE_SYSNOTICE = 9999;
// public static final int MSGTYPE_POSSIBLEFRIEND_MSG = 40;
// public static final int MSGTYPE_VERIFYMSG = 37;
// public static final int MSGTYPE_SHARECARD = 42;
// public static final int MSGTYPE_SYS = 10000;
// public static final int MSGTYPE_RECALLED = 10002;
MSGTYPE_TEXT(1, "文本消息类型"),
MSGTYPE_IMAGE(3, "图片消息"),
MSGTYPE_VOICE(34, "语音消息"),
MSGTYPE_VIDEO(43, "小视频消息"),
MSGTYPE_MICROVIDEO(62, "短视频消息"),
MSGTYPE_EMOTICON(47, "表情消息"),
MSGTYPE_MEDIA(49, "多媒体消息"),
MSGTYPE_VOIPMSG(50, ""),
MSGTYPE_VOIPNOTIFY(52, ""),
MSGTYPE_VOIPINVITE(53, ""),
MSGTYPE_LOCATION(48, ""),
MSGTYPE_STATUSNOTIFY(51, ""),
MSGTYPE_SYSNOTICE(9999, ""),
MSGTYPE_POSSIBLEFRIEND_MSG(40, ""),
MSGTYPE_VERIFYMSG(37, "好友请求"),
MSGTYPE_SHARECARD(42, ""),
MSGTYPE_SYS(10000, "系统消息"),
MSGTYPE_RECALLED(10002, "")
;
private int code;
private String type;
MsgCodeEnum(int code, String type) {
this.code = code;
this.type = type;
}
public int getCode() {
return code;
}
public String getType() {
return type;
}
}

@ -0,0 +1,38 @@
package cn.zhouyafeng.itchat4j.utils.enums;
/**
*
*
* @author https://github.com/yaphone
* @date 2017513 11:53:00
* @version 1.0
*
*/
public enum MsgTypeEnum {
TEXT("Text", "文本消息"),
PIC("Pic", "图片消息"),
VOICE("Voice", "语音消息"),
VIEDO("Viedo", "小视频消息"),
NAMECARD("NameCard", "名片消息"),
SYS("Sys", "系统消息"),
VERIFYMSG("VerifyMsg", "添加好友"),
MEDIA("app", "文件消息");
private String type;
private String code;
MsgTypeEnum(String type, String code) {
this.type = type;
this.code = code;
}
public String getType() {
return type;
}
public String getCode() {
return code;
}
}

@ -0,0 +1,13 @@
package cn.zhouyafeng.itchat4j.utils.enums;
/**
*
*
* @author https://github.com/yaphone
* @date 201748 10:36:28
* @version 1.0
*
*/
public enum OsNameEnum {
WINDOWS, LINUX, DARWIN, MAC, OTHER
}

@ -0,0 +1,35 @@
package cn.zhouyafeng.itchat4j.utils.enums;
/**
*
* <p>
* Created by xiaoxiaomo on 2017/5/6.
*/
public enum ResultEnum {
SUCCESS("200", "成功"),
WAIT_CONFIRM("201", "请在手机上点击确认"),
WAIT_SCAN("400", "请扫描二维码");
private String code;
private String msg;
ResultEnum(String code, String msg) {
this.code = code;
this.msg = msg;
}
public String getCode() {
return code;
}
// public static MsgInfoEnum getCode(String code) {
// switch (code) {
// case "Text":
// return MsgInfoEnum.TEXT;
// default:
// return MsgInfoEnum.VIDEO;
// }
// }
}

@ -0,0 +1,30 @@
package cn.zhouyafeng.itchat4j.utils.enums;
public enum RetCodeEnum {
NORMAL("0", "普通"),
LOGIN_OUT("1102", "退出"),
LOGIN_OTHERWHERE("1101", "其它地方登陆"),
MOBILE_LOGIN_OUT("1102", "移动端退出"),
UNKOWN("9999", "未知")
;
private String code;
private String type;
RetCodeEnum(String code, String type) {
this.code = code;
this.type = type;
}
public String getCode() {
return code;
}
public String getType() {
return type;
}
}

@ -0,0 +1,59 @@
package cn.zhouyafeng.itchat4j.utils.enums;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import java.util.HashMap;
import java.util.Map;
/**
* Created by xiaoxiaomo on 2017/5/7.
*/
public enum StorageLoginInfoEnum {
//URL
url("url",new String()),
fileUrl("fileUrl",new String()),
syncUrl("syncUrl",new String()),
deviceid("deviceid",new String()), //生成15位随机数
//baseRequest
skey("skey",new String()),
wxsid("wxsid",new String()),
wxuin("wxuin",new String()),
pass_ticket("pass_ticket",new String()),
InviteStartCount("InviteStartCount",new Integer(0)),
User("User",new JSONObject()),
SyncKey("SyncKey",new JSONObject()),
synckey("synckey",new String()),
MemberCount("MemberCount",new String()),
MemberList("MemberList",new JSONArray()),
;
private String key;
private Object type;
StorageLoginInfoEnum(String key, Object type) {
this.key = key;
this.type = type;
}
public String getKey() {
return key;
}
public Object getType() {
return type;
}
}

@ -0,0 +1,49 @@
package cn.zhouyafeng.itchat4j.utils.enums;
/**
* URL
* Created by xiaoxiaomo on 2017/5/6.
*/
public enum URLEnum {
BASE_URL("https://login.weixin.qq.com","基本的URL"),
UUID_URL(BASE_URL.url+"/jslogin","UUIDLURL"),
QRCODE_URL(BASE_URL.url+"/qrcode/","初始化URL"),
STATUS_NOTIFY_URL(BASE_URL.url+"/webwxstatusnotify?lang=zh_CN&pass_ticket=%s","微信状态通知"),
LOGIN_URL(BASE_URL.url+"/cgi-bin/mmwebwx-bin/login","登陆URL"),
INIT_URL("%s/webwxinit?r=%s&pass_ticket=%s","初始化URL"),
SYNC_CHECK_URL("/synccheck","检查心跳URL"),
WEB_WX_SYNC_URL("%s/webwxsync?sid=%s&skey=%s&pass_ticket=%s","web微信消息同步URL"),
WEB_WX_GET_CONTACT("%s/webwxgetcontact","web微信获取联系人信息URL"),
WEB_WX_SEND_MSG("%s/webwxsendmsg","发送消息URL"),
WEB_WX_UPLOAD_MEDIA("%s/webwxuploadmedia?f=json", "上传文件到服务器"),
WEB_WX_GET_MSG_IMG("%s/webwxgetmsgimg", "下载图片消息"),
WEB_WX_GET_VOICE("%s/webwxgetvoice", "下载语音消息"),
WEB_WX_GET_VIEDO("%s/webwxgetvideo", "下载语音消息"),
WEB_WX_PUSH_LOGIN("%s/webwxpushloginurl", "不扫码登陆"),
WEB_WX_LOGOUT("%s/webwxlogout", "退出微信"),
WEB_WX_BATCH_GET_CONTACT("%s/webwxbatchgetcontact?type=ex&r=%s&lang=zh_CN&pass_ticket=%s", "查询群信息"),
WEB_WX_REMARKNAME("%s/webwxoplog?lang=zh_CN&pass_ticket=%s", "修改好友备注"),
WEB_WX_VERIFYUSER("%s/webwxverifyuser?r=%s&lang=zh_CN&pass_ticket=%s", "被动添加好友"),
WEB_WX_GET_MEDIA("%s/webwxgetmedia", "下载文件")
;
private String url;
private String msg;
URLEnum(String url, String msg) {
this.url = url;
this.msg = msg;
}
public String getUrl() {
return url;
}
}

@ -0,0 +1,28 @@
package cn.zhouyafeng.itchat4j.utils.enums;
/**
* Enum
*
* @author https://github.com/yaphone
* @date 2017629 9:47:14
* @version 1.0
*
*/
public enum VerifyFriendEnum {
ADD(2, "添加"),
ACCEPT(3, "接受");
private int code;
private String desc;
private VerifyFriendEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() {
return code;
}
}

@ -0,0 +1,36 @@
package cn.zhouyafeng.itchat4j.utils.enums.parameters;
/**
*
*
* 1. webWxInit
* 2. wxStatusNotify
*
* <p>
* Created by xiaoxiaomo on 2017/5/7.
*/
public enum BaseParaEnum {
Uin("Uin", "wxuin"),
Sid("Sid", "wxsid"),
Skey("Skey", "skey"),
DeviceID("DeviceID", "pass_ticket");
private String para;
private String value;
BaseParaEnum(String para, String value) {
this.para = para;
this.value = value;
}
public String para() {
return para;
}
public Object value() {
return value;
}
}

@ -0,0 +1,31 @@
package cn.zhouyafeng.itchat4j.utils.enums.parameters;
/**
*
* <p>
* Created by xiaoxiaomo on 2017/5/7.
*/
public enum LoginParaEnum {
LOGIN_ICON("loginicon", "true"),
UUID("uuid", ""),
TIP("tip", "0"),
R("r", ""),
_("_", "");
private String para;
private String value;
LoginParaEnum(String para, String value) {
this.para = para;
this.value = value;
}
public String para() {
return para;
}
public String value() {
return value;
}
}

@ -0,0 +1,30 @@
package cn.zhouyafeng.itchat4j.utils.enums.parameters;
/**
*
* <p>
* Created by xiaoxiaomo on 2017/5/7.
*/
public enum StatusNotifyParaEnum {
CODE("Code", "3"),
FROM_USERNAME("FromUserName", ""),
TO_USERNAME("ToUserName", ""),
CLIENT_MSG_ID("ClientMsgId", ""); //时间戳
private String para;
private String value;
StatusNotifyParaEnum(String para, String value) {
this.para = para;
this.value = value;
}
public String para() {
return para;
}
public String value() {
return value;
}
}

@ -0,0 +1,30 @@
package cn.zhouyafeng.itchat4j.utils.enums.parameters;
/**
* UUID
* <p>
* Created by xiaoxiaomo on 2017/5/7.
*/
public enum UUIDParaEnum {
APP_ID("appid", "wx782c26e4c19acffb"),
FUN("fun", "new"),
LANG("lang", "zh_CN"),
_("_", "时间戳");
private String para;
private String value;
UUIDParaEnum(String para, String value) {
this.para = para;
this.value = value;
}
public String para() {
return para;
}
public String value() {
return value;
}
}

@ -0,0 +1,243 @@
package cn.zhouyafeng.itchat4j.utils.tools;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.vdurmont.emoji.EmojiParser;
import cn.zhouyafeng.itchat4j.utils.Config;
import cn.zhouyafeng.itchat4j.utils.enums.OsNameEnum;
/**
*
*
* @author https://github.com/yaphone
* @date 201748 10:59:55
* @version 1.0
*
*/
public class CommonTools {
public static boolean printQr(String qrPath) {
switch (Config.getOsNameEnum()) {
case WINDOWS:
if (Config.getOsNameEnum().equals(OsNameEnum.WINDOWS)) {
Runtime runtime = Runtime.getRuntime();
try {
runtime.exec("cmd /c start " + qrPath);
} catch (Exception e) {
e.printStackTrace();
}
}
break;
case MAC:
if (Config.getOsNameEnum().equals(OsNameEnum.MAC)) {
Runtime runtime = Runtime.getRuntime();
try {
runtime.exec("open " + qrPath);
} catch (Exception e) {
e.printStackTrace();
}
}
break;
default:
break;
}
return true;
}
public static boolean clearScreen() {
switch (Config.getOsNameEnum()) {
case WINDOWS:
if (Config.getOsNameEnum().equals(OsNameEnum.WINDOWS)) {
Runtime runtime = Runtime.getRuntime();
try {
runtime.exec("cmd /c " + "cls");
} catch (Exception e) {
e.printStackTrace();
}
}
break;
default:
break;
}
return true;
}
/**
*
*
* @author https://github.com/yaphone
* @date 201749 12:27:10
* @return
*/
public static Matcher getMatcher(String regEx, String text) {
Pattern pattern = Pattern.compile(regEx);
Matcher matcher = pattern.matcher(text);
return matcher;
}
/**
* xml
*
* @author https://github.com/yaphone
* @date 201749 6:24:25
* @param text
* @return
*/
public static Document xmlParser(String text) {
Document doc = null;
StringReader sr = new StringReader(text);
InputSource is = new InputSource(sr);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = factory.newDocumentBuilder();
doc = builder.parse(is);
} catch (Exception e) {
e.printStackTrace();
}
return doc;
}
public static JSONObject structFriendInfo(JSONObject userObj) {
Map<String, Object> friendInfoTemplate = new HashMap<String, Object>();
friendInfoTemplate.put("UserName", "");
friendInfoTemplate.put("City", "");
friendInfoTemplate.put("DisplayName", "");
friendInfoTemplate.put("PYQuanPin", "");
friendInfoTemplate.put("RemarkPYInitial", "");
friendInfoTemplate.put("Province", "");
friendInfoTemplate.put("KeyWord", "");
friendInfoTemplate.put("RemarkName", "");
friendInfoTemplate.put("PYInitial", "");
friendInfoTemplate.put("EncryChatRoomId", "");
friendInfoTemplate.put("Alias", "");
friendInfoTemplate.put("Signature", "");
friendInfoTemplate.put("NickName", "");
friendInfoTemplate.put("RemarkPYQuanPin", "");
friendInfoTemplate.put("HeadImgUrl", "");
friendInfoTemplate.put("UniFriend", 0);
friendInfoTemplate.put("Sex", 0);
friendInfoTemplate.put("AppAccountFlag", 0);
friendInfoTemplate.put("VerifyFlag", 0);
friendInfoTemplate.put("ChatRoomId", 0);
friendInfoTemplate.put("HideInputBarFlag", 0);
friendInfoTemplate.put("AttrStatus", 0);
friendInfoTemplate.put("SnsFlag", 0);
friendInfoTemplate.put("MemberCount", 0);
friendInfoTemplate.put("OwnerUin", 0);
friendInfoTemplate.put("ContactFlag", 0);
friendInfoTemplate.put("Uin", 0);
friendInfoTemplate.put("StarFriend", 0);
friendInfoTemplate.put("Statues", 0);
friendInfoTemplate.put("MemberList", new ArrayList<Object>());
JSONObject r = new JSONObject();
Set<String> keySet = friendInfoTemplate.keySet();
for (String key : keySet) {
if (userObj.containsKey(key)) {
r.put(key, userObj.get(key));
} else {
r.put(key, friendInfoTemplate.get(key));
}
}
return r;
}
public static String getSynckey(JSONObject obj) {
JSONArray obj2 = obj.getJSONArray("List");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < obj2.size(); i++) {
JSONObject obj3 = (JSONObject) JSON.toJSON(obj2.get(i));
sb.append(obj3.get("Val") + "|");
}
return sb.substring(0, sb.length() - 1); // 656159784|656159911|656159873|1491905341
}
public static JSONObject searchDictList(List<JSONObject> list, String key, String value) {
JSONObject r = null;
for (JSONObject i : list) {
if (i.getString(key).equals(value)) {
r = i;
break;
}
}
return r;
}
/**
* emoji
*
* @author https://github.com/yaphone
* @date 2017423 2:39:04
* @param d
* @param k
*/
public static void emojiFormatter(JSONObject d, String k) {
Matcher matcher = getMatcher("<span class=\"emoji emoji(.{1,10})\"></span>", d.getString(k));
StringBuilder sb = new StringBuilder();
String content = d.getString(k);
int lastStart = 0;
while (matcher.find()) {
String str = matcher.group(1);
if (str.length() == 6) {
} else if (str.length() == 10) {
} else {
str = "&#x" + str + ";";
String tmp = content.substring(lastStart, matcher.start());
sb.append(tmp + str);
lastStart = matcher.end();
}
}
if (lastStart < content.length()) {
sb.append(content.substring(lastStart));
}
if (sb.length() != 0) {
d.put(k, EmojiParser.parseToUnicode(sb.toString()));
} else {
d.put(k, content);
}
}
/**
*
*
* @author https://github.com/yaphone
* @date 2017423 4:19:08
* @param d
* @param k
*/
public static void msgFormatter(JSONObject d, String k) {
d.put(k, d.getString(k).replace("<br/>", "\n"));
emojiFormatter(d, k);
// TODO 与emoji表情有部分兼容问题目前暂未处理解码处理 d.put(k,
// StringEscapeUtils.unescapeHtml4(d.getString(k)));
}
}

@ -0,0 +1,80 @@
package cn.zhouyafeng.itchat4j.utils.tools;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.apache.http.HttpEntity;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import cn.zhouyafeng.itchat4j.beans.BaseMsg;
import cn.zhouyafeng.itchat4j.core.Core;
import cn.zhouyafeng.itchat4j.utils.MyHttpClient;
import cn.zhouyafeng.itchat4j.utils.enums.MsgTypeEnum;
import cn.zhouyafeng.itchat4j.utils.enums.URLEnum;
/**
*
*
* @author https://github.com/yaphone
* @date 2017421 11:18:46
* @version 1.0
*
*/
public class DownloadTools {
private static Logger logger = Logger.getLogger("DownloadTools");
private static Core core = Core.getInstance();
private static MyHttpClient myHttpClient = core.getMyHttpClient();
/**
*
*
* @author https://github.com/yaphone
* @date 2017421 11:00:25
* @param url
* @param msgId
* @param path
* @return
*/
public static Object getDownloadFn(BaseMsg msg, String type, String path) {
Map<String, String> headerMap = new HashMap<String, String>();
List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
String url = "";
if (type.equals(MsgTypeEnum.PIC.getType())) {
url = String.format(URLEnum.WEB_WX_GET_MSG_IMG.getUrl(), (String) core.getLoginInfo().get("url"));
} else if (type.equals(MsgTypeEnum.VOICE.getType())) {
url = String.format(URLEnum.WEB_WX_GET_VOICE.getUrl(), (String) core.getLoginInfo().get("url"));
} else if (type.equals(MsgTypeEnum.VIEDO.getType())) {
headerMap.put("Range", "bytes=0-");
url = String.format(URLEnum.WEB_WX_GET_VIEDO.getUrl(), (String) core.getLoginInfo().get("url"));
} else if (type.equals(MsgTypeEnum.MEDIA.getType())) {
headerMap.put("Range", "bytes=0-");
url = String.format(URLEnum.WEB_WX_GET_MEDIA.getUrl(), (String) core.getLoginInfo().get("fileUrl"));
params.add(new BasicNameValuePair("sender", msg.getFromUserName()));
params.add(new BasicNameValuePair("mediaid", msg.getMediaId()));
params.add(new BasicNameValuePair("filename", msg.getFileName()));
}
params.add(new BasicNameValuePair("msgid", msg.getNewMsgId()));
params.add(new BasicNameValuePair("skey", (String) core.getLoginInfo().get("skey")));
HttpEntity entity = myHttpClient.doGet(url, params, true, headerMap);
try {
OutputStream out = new FileOutputStream(path);
byte[] bytes = EntityUtils.toByteArray(entity);
out.write(bytes);
out.flush();
out.close();
// Tools.printQr(path);
} catch (Exception e) {
logger.info(e.getMessage());
return false;
}
return null;
};
}

@ -0,0 +1,79 @@
package xyz.wbsite.itchat4j;
import cn.hutool.core.io.FileUtil;
import cn.zhouyafeng.itchat4j.Wechat;
import cn.zhouyafeng.itchat4j.face.IMsgHandlerFace;
import com.melloware.jintellitype.JIntellitype;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import xyz.wbsite.itchat4j.ui.FXMLUtil;
import xyz.wbsite.itchat4j.util.ResourceUtil;
import java.awt.event.KeyEvent;
import java.io.File;
/**
* UI
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public class JMainApplication extends Application {
public static final int F1_SHORTCUT = 1; // 开始快捷键
public static final int F2_SHORTCUT = 2; // 结束快捷键
public static Stage primaryStage;
public static JMainController mainController;
@Override
public void start(Stage stage) throws Exception {
stage.setTitle("微信客户端");
stage.setMinWidth(400);
stage.setMinHeight(300);
FXMLLoader mainLoader = FXMLUtil.load("main.fxml");
mainController = mainLoader.getController();
stage.setScene(new Scene(mainLoader.getRoot()));
stage.centerOnScreen();
stage.setResizable(false);
stage.setOnCloseRequest(event -> {
stage.close();
System.exit(0);
});
// 设置图标
Image icon = new Image(ResourceUtil.getInput("/icon.png"));
stage.getIcons().add(icon);
// 展示UI
stage.show();
JMainApplication.primaryStage = stage;
JIntellitype.getInstance().registerHotKey(F1_SHORTCUT, JIntellitype.MOD_CONTROL, KeyEvent.VK_F1);
JIntellitype.getInstance().registerHotKey(F2_SHORTCUT, JIntellitype.MOD_CONTROL, KeyEvent.VK_F2);
JIntellitype.getInstance().addHotKeyListener(identifier -> {
switch (identifier) {
case F1_SHORTCUT:
mainController.onStart();
break;
case F2_SHORTCUT:
mainController.onStop();
break;
}
});
// FileUtil.file(FileUtil.getTmpDir(), "itchat4j.");
String qrPath = "C:\\Users\\Administrator\\Desktop\\111"; // 保存登陆二维码图片的路径,这里需要在本地新建目录
IMsgHandlerFace msgHandler = new JMsgHandler(); // 实现IMsgHandlerFace接口的类
Wechat wechat = new Wechat(msgHandler, qrPath); // 【注入】
// 启动服务会在qrPath下生成一张二维码图片扫描即可登陆注意二维码图片如果超过一定时间未扫描会过期过期时会自动更新所以你可能需要重新打开图片
wechat.start();
}
public static void main(String[] args) {
launch(args);
}
}

@ -0,0 +1,172 @@
package xyz.wbsite.itchat4j;
import cn.hutool.core.collection.BoundedPriorityQueue;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.StrUtil;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.util.Duration;
import xyz.wbsite.itchat4j.util.Logger;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.concurrent.Semaphore;
/**
* UI
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public class JMainController implements Initializable {
/**
*
*/
private static JMainController instance;
@FXML
private Button start;
@FXML
private Button stop;
@FXML
private ImageView set;
@FXML
private TextField interval;
@FXML
private TextField times;
@FXML
private ImageView preview;
@FXML
private TextArea console;
private final int MAX_LENGTH = 100;
private final BoundedPriorityQueue<String> logs = new BoundedPriorityQueue<>(MAX_LENGTH);
private Semaphore semaphore = new Semaphore(1);
public static synchronized JMainController getInstance() {
return JMainController.instance;
}
@Override
public void initialize(URL location, ResourceBundle resources) {
JMainController.instance = this;
// 控件初始化
// int intervalValue = JProp.getInstance().getInt("interval", 60);
// this.interval.setText(String.valueOf(intervalValue));
// // 只允许输入数字
// this.interval.textProperty().addListener((observable, oldValue, newValue) -> {
// if (!newValue.matches("\\d*")) {
// this.interval.setText(newValue.replaceAll("\\D", ""));
// }
// JProp.getInstance().setInt("interval", Convert.toInt(this.times.getText()));
// });
// int timesValue = JProp.getInstance().getInt("times", 3);
// this.times.setText(String.valueOf(timesValue));
// this.times.textProperty().addListener((observable, oldValue, newValue) -> {
// if (!newValue.matches("\\d*")) {
// this.times.setText(newValue.replaceAll("\\D", ""));
// }
// JProp.getInstance().setInt("times", Convert.toInt(this.times.getText()));
// });
// installTip(this.set, "扩展配置");
// installTip(this.interval, "两次脚本执行的间隔时间(秒)");
// installTip(this.times, "脚本执行的总次数0代表无限循环");
}
/**
*
*/
@FXML
public void onStart() {
synchronized (JMainController.class) {
this.start.setDisable(true);
this.stop.setDisable(false);
Logger.info("启动服务");
}
}
/**
*
*/
@FXML
public void onStop() {
synchronized (JMainController.class) {
this.start.setDisable(false);
this.stop.setDisable(true);
Logger.info("停止服务");
}
}
/**
*
*
* @param image
*/
public void preview(Image image) {
try {
semaphore.acquire();
preview.setImage(image);
Thread.sleep(500);
semaphore.release();
} catch (InterruptedException e) {
semaphore.release();
throw new RuntimeException(e);
}
}
/**
*
*
* @param log
* @param args
*/
public synchronized void println(String log, Object... args) {
Platform.runLater(() -> {
String format = StrUtil.format(log, args) + "\n";
if (logs.size() >= MAX_LENGTH) {
String poll = logs.poll();
console.deleteText(0, poll.length());
}
logs.add(format);
console.appendText(format);
});
}
/**
*
*
* @param node
* @param tip
*/
public static void installTip(Node node, String tip) {
Tooltip tooltip = new Tooltip(tip);
try {
java.lang.reflect.Field behavior = ClassUtil.getDeclaredField(Tooltip.class, "BEHAVIOR");
behavior.setAccessible(true);
Object o = behavior.get(tooltip);
java.lang.reflect.Field activationTimer = ClassUtil.getDeclaredField(o.getClass(), "activationTimer");
activationTimer.setAccessible(true);
Timeline timeline = (Timeline) activationTimer.get(o);
timeline.getKeyFrames().remove(0);
timeline.getKeyFrames().add(new KeyFrame(new Duration(10)));
Tooltip.install(node, tooltip);
} catch (Exception e) {
}
}
}

@ -0,0 +1,46 @@
package xyz.wbsite.itchat4j;
import cn.zhouyafeng.itchat4j.beans.BaseMsg;
import cn.zhouyafeng.itchat4j.face.IMsgHandlerFace;
public class JMsgHandler implements IMsgHandlerFace {
@Override
public String textMsgHandle(BaseMsg baseMsg) {
return baseMsg.getText();
}
@Override
public String picMsgHandle(BaseMsg baseMsg) {
return null;
}
@Override
public String voiceMsgHandle(BaseMsg baseMsg) {
return null;
}
@Override
public String viedoMsgHandle(BaseMsg baseMsg) {
return null;
}
@Override
public String nameCardMsgHandle(BaseMsg baseMsg) {
return null;
}
@Override
public void sysMsgHandle(BaseMsg baseMsg) {
}
@Override
public String verifyAddFriendMsgHandle(BaseMsg baseMsg) {
return null;
}
@Override
public String mediaMsgHandle(BaseMsg baseMsg) {
return null;
}
}

@ -0,0 +1,92 @@
package xyz.wbsite.itchat4j;
import cn.hutool.core.io.FileUtil;
import cn.hutool.setting.dialect.Props;
import java.io.File;
import java.nio.charset.StandardCharsets;
/**
*
*/
public class JProp {
private static final JProp instance = new JProp();
private final File propFile;
private final Props props;
public static JProp getInstance() {
return instance;
}
private JProp() {
this.propFile = new File("prop.ini");
if (!propFile.exists()) {
FileUtil.touch(propFile.getAbsolutePath());
this.props = new Props(propFile, StandardCharsets.UTF_8);
// 做一些初始化操作
} else {
this.props = new Props(propFile, StandardCharsets.UTF_8);
}
}
private void save() {
this.props.store(propFile.getAbsolutePath());
}
public String getString(String key, String defaultValue) {
return this.props.getStr(key, defaultValue);
}
public String[] getStringArray(String key, String[] defaultValue) {
return this.props.getStr(key, "").split(",");
}
public int getInt(String key, int defaultValue) {
return this.props.getInt(key, defaultValue);
}
public long getLong(String key, long defaultValue) {
return this.props.getLong(key, defaultValue);
}
public float getFloat(String key, float defaultValue) {
return this.props.getFloat(key, defaultValue);
}
public double getDouble(String key, double defaultValue) {
return this.props.getDouble(key, defaultValue);
}
public void setString(String key, String value) {
this.props.setProperty(key, value);
this.save();
}
public void setStringArray(String key, String[] value) {
this.props.setProperty(key, String.join(",", value));
this.save();
}
public void setInt(String key, int value) {
this.props.setProperty(key, String.valueOf(value));
this.save();
}
public void setLong(String key, long value) {
this.props.setProperty(key, String.valueOf(value));
this.save();
}
public void setFloat(String key, float value) {
this.props.setProperty(key, String.valueOf(value));
this.save();
}
public void setDouble(String key, double value) {
this.props.setProperty(key, String.valueOf(value));
this.save();
}
}

@ -0,0 +1,151 @@
package xyz.wbsite.itchat4j.db;
import java.io.File;
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Types;
/**
* xyz.wbsite.wsqlite.Client
*
* @author wangbing
*/
public class Client {
Connection connection;
ResultSet resultSet;
String dbFilePath;
/**
*
*
* @param dbFile
* @throws ClassNotFoundException
* @throws SQLException
*/
public Client(File dbFile) throws ClassNotFoundException, SQLException {
this.dbFilePath = dbFile.getAbsolutePath();
if (!dbFile.exists()) {
connection = getConnection();
}
}
/**
* sql
*
* @param sql
* @throws SQLException
* @throws ClassNotFoundException
*/
public void execute(String sql) throws SQLException, ClassNotFoundException {
try {
executeUpdate(sql);
} finally {
destroyed();
}
}
/**
* sql
*
* @param sql
* @throws SQLException
* @throws ClassNotFoundException
*/
public ResultSet executeQuery(String sql, Object... args) throws SQLException, ClassNotFoundException {
PreparedStatement preparedStatement = getConnection().prepareStatement(sql);
setArg(preparedStatement, args);
return preparedStatement.executeQuery();
}
/**
* sql
*
* @param sql
* @throws SQLException
* @throws ClassNotFoundException
*/
public int executeUpdate(String sql, Object... args) throws SQLException, ClassNotFoundException {
try {
PreparedStatement preparedStatement = getConnection().prepareStatement(sql);
setArg(preparedStatement, args);
return preparedStatement.executeUpdate();
} finally {
destroyed();
}
}
private void setArg(PreparedStatement ps, Object... args) throws SQLException {
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
if (arg == null) {
ps.setNull(i + 1, Types.NULL);
} else if (arg instanceof String) {
ps.setString(i + 1, (String) arg);
} else if (arg instanceof Date) {
ps.setDate(i + 1, (Date) arg);
} else if (arg instanceof Time) {
ps.setTime(i + 1, (Time) arg);
} else if (arg instanceof java.util.Date) {
ps.setLong(i + 1, ((java.util.Date) arg).getTime());
} else if (arg instanceof Boolean) {
ps.setBoolean(i + 1, (Boolean) arg);
} else if (arg instanceof Byte) {
ps.setByte(i + 1, (Byte) arg);
} else if (arg instanceof Short) {
ps.setShort(i + 1, (Short) arg);
} else if (arg instanceof Integer) {
ps.setInt(i + 1, (int) arg);
} else if (arg instanceof Long) {
ps.setLong(i + 1, (long) arg);
} else if (arg instanceof Float) {
ps.setFloat(i + 1, (float) arg);
} else if (arg instanceof Double) {
ps.setDouble(i + 1, (double) arg);
} else if (arg instanceof byte[]) {
ps.setBytes(i + 1, (byte[]) arg);
}
}
}
/**
*
*
* @return
* @throws ClassNotFoundException
* @throws SQLException
*/
Connection getConnection() throws ClassNotFoundException, SQLException {
if (null == connection) {
Class.forName("org.sqlite.JDBC");
connection = DriverManager.getConnection("jdbc:sqlite:" + dbFilePath);
}
return connection;
}
/**
*
*/
public void destroyed() {
try {
if (null != resultSet) {
resultSet.close();
resultSet = null;
}
if (null != connection) {
connection.close();
connection = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}

@ -0,0 +1,323 @@
package xyz.wbsite.itchat4j.db;
import xyz.wbsite.itchat4j.db.anonation.TableField;
import java.io.File;
import java.lang.reflect.Field;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* xyz.wbsite.wsqlite.Client
*
* @author wangbing
*/
public class ObjectClient extends Client {
private Map<String, Class> classMap = new HashMap<>();
/**
*
*
* @param dbFile
* @param classList
* @throws ClassNotFoundException
* @throws SQLException
*/
public ObjectClient(File dbFile, List<Class> classList) throws ClassNotFoundException, SQLException {
super(dbFile);
for (Class aClass : classList) {
classMap.put(aClass.getName(), aClass);
}
for (String key : classMap.keySet()) {
Class object = classMap.get(key);
StringBuffer sql = new StringBuffer();
String name = object.getSimpleName();
sql.append("CREATE TABLE IF NOT EXISTS ");
sql.append(name);
sql.append(" (");
Field[] fields = object.getDeclaredFields();
for (Field f : fields) {
if (f.isAnnotationPresent(TableField.class)) {
TableField bind = f.getAnnotation(TableField.class);
int length = bind.value();
if (f.getType() == String.class) {
sql.append(f.getName().toUpperCase());
sql.append(" VARCHAR(" + length + "),");
} else if (f.getType() == Boolean.class || f.getType() == boolean.class) {
sql.append(f.getName().toUpperCase());
sql.append(" BOOLEAN,");
} else if (f.getType() == Byte.class || f.getType() == byte.class ||
f.getType() == Short.class || f.getType() == short.class ||
f.getType() == Character.class || f.getType() == char.class ||
f.getType() == Integer.class || f.getType() == int.class ||
f.getType() == Long.class || f.getType() == long.class) {
sql.append(f.getName().toUpperCase());
sql.append(" INTEGER,");
} else if (f.getType() == Float.class || f.getType() == float.class ||
f.getType() == Double.class || f.getType() == double.class) {
sql.append(f.getName().toUpperCase());
sql.append(" REAL,");
} else if (f.getType() == Byte[].class || f.getType() == byte[].class) {
sql.append(f.getName().toUpperCase());
sql.append(" BLOB,");
} else if (f.getType() == Date.class) {
sql.append(f.getName().toUpperCase());
sql.append(" TIMESTAMP,");
}
}
}
sql.replace(sql.length() - 1, sql.length(), "");
sql.append(")");
System.out.println("SQL ==> " + sql.toString());
execute(sql.toString());
}
}
public <T> int insert(Class<T> poClass, T po) throws SQLException, ClassNotFoundException {
try {
Class aClass = classMap.get(poClass.getName());
if (aClass == null) {
System.err.println(poClass.getName() + " not found.");
} else {
StringBuffer sql = new StringBuffer();
sql.append("INSERT INTO ");
sql.append(aClass.getSimpleName());
sql.append("(");
//获取字段列表
List<Field> fs = getFields(poClass);
StringBuffer fieldsSql = new StringBuffer();
StringBuffer valueSql = new StringBuffer();
Object[] values = new Object[fs.size()];
for (int i = 0; i < fs.size(); i++) {
Field f = fs.get(i);
f.setAccessible(true);
fieldsSql.append(f.getName().toUpperCase());
valueSql.append("?");
values[i] = f.get(po);
if (i != fs.size() - 1) {
fieldsSql.append(",");
valueSql.append(",");
}
}
sql.append(fieldsSql);
sql.append(") VALUES (");
sql.append(valueSql);
sql.append(")");
System.out.println("SQL ==> " + sql.toString());
return executeUpdate(sql.toString(), values);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} finally {
destroyed();
}
return 0;
}
public <T> int delete(Class<T> poClass, Where where) throws SQLException, ClassNotFoundException {
try {
Class aClass = classMap.get(poClass.getName());
if (aClass == null) {
System.err.println(poClass.getName() + " not found.");
} else {
StringBuffer sql = new StringBuffer();
sql.append("DELETE FROM ");
sql.append(aClass.getSimpleName());
sql.append(where.getSql());
System.out.println("SQL ==> " + sql.toString());
return executeUpdate(sql.toString(), where.getArgs());
}
} finally {
destroyed();
}
return 0;
}
public <T> int update(Class<T> poClass, T po, Where where) throws SQLException, ClassNotFoundException {
try {
Class aClass = classMap.get(poClass.getName());
if (aClass == null) {
System.err.println(poClass.getName() + " not found.");
} else {
//获取字段列表
List<Field> fs = getFields(poClass);
StringBuffer sql = new StringBuffer();
Object[] values = new Object[fs.size()];
sql.append("UPDATE ");
sql.append(aClass.getSimpleName());
sql.append(" SET ");
for (int i = 0; i < fs.size(); i++) {
Field f = fs.get(i);
f.setAccessible(true);
sql.append(f.getName());
sql.append(" = ?");
values[i] = f.get(po);
if (i != fs.size() - 1) {
sql.append(",");
}
}
// 条件
sql.append(where.getSql());
System.out.println("SQL ==> " + sql.toString());
return executeUpdate(sql.toString(), concat(values, where.getArgs()));
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} finally {
destroyed();
}
return 0;
}
public <T> List<T> select(Class<T> poClass, Where where, int pageNumber, int pageSize) throws SQLException, ClassNotFoundException {
ArrayList<T> list = new ArrayList<>();
try {
Class aClass = classMap.get(poClass.getName());
if (aClass == null) {
System.err.println(poClass.getName() + " not found.");
} else {
StringBuffer sql = new StringBuffer();
sql.append("SELECT ");
//获取字段列表
List<Field> fs = getFields(poClass);
for (int i = 0; i < fs.size(); i++) {
Field f = fs.get(i);
sql.append(f.getName().toUpperCase());
if (i != fs.size() - 1) {
sql.append(",");
}
}
sql.append(" FROM ");
sql.append(aClass.getSimpleName());
// 条件
sql.append(where.getSql());
//分页参数
if (pageSize > 0) {
sql.append(" LIMIT " + (pageNumber - 1) + "," + pageSize);
}
System.out.println("SQL ==> " + sql.toString());
list.addAll(executeQuery(poClass, sql.toString(), where.getArgs()));
}
} finally {
destroyed();
}
return list;
}
/**
* select
*
* @param sql sql select
* @param poClass
* @return
* @throws SQLException
* @throws ClassNotFoundException
*/
public <T> List<T> executeQuery(Class<T> poClass, String sql, Object... args) throws SQLException, ClassNotFoundException {
List<T> rsList = new ArrayList<T>();
try {
resultSet = executeQuery(sql, args);
//获取字段列表
List<Field> fs = getFields(poClass);
while (resultSet.next()) {
try {
T o = poClass.newInstance();
for (int i = 0; i < fs.size(); i++) {
Field f = fs.get(i);
f.setAccessible(true);
if (f.getType() == String.class) {
String v = resultSet.getString(f.getName());
f.set(o, v);
} else if (f.getType() == Boolean.class || f.getType() == boolean.class) {
boolean v = resultSet.getBoolean(f.getName());
f.set(o, v);
} else if (f.getType() == Byte.class || f.getType() == byte.class) {
byte v = resultSet.getByte(f.getName());
f.set(o, v);
} else if (f.getType() == Short.class || f.getType() == short.class) {
short v = resultSet.getShort(f.getName());
f.set(o, v);
} else if (f.getType() == Character.class || f.getType() == char.class) {
short v = resultSet.getShort(f.getName());
f.set(o, (char) v);
} else if (f.getType() == Integer.class || f.getType() == int.class) {
int v = resultSet.getInt(f.getName());
f.set(o, v);
} else if (f.getType() == Long.class || f.getType() == long.class) {
long v = resultSet.getLong(f.getName());
f.set(o, v);
} else if (f.getType() == Float.class || f.getType() == float.class) {
float v = resultSet.getFloat(f.getName());
f.set(o, v);
} else if (f.getType() == Double.class || f.getType() == double.class) {
double v = resultSet.getDouble(f.getName());
f.set(o, v);
} else if (f.getType() == Byte[].class || f.getType() == byte[].class) {
byte[] v = resultSet.getBytes(f.getName());
f.set(o, v);
} else if (f.getType() == Date.class) {
Date v = resultSet.getDate(f.getName());
f.set(o, v);
} else {
String v = resultSet.getString(f.getName());
f.set(o, v);
}
}
rsList.add(o);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
} finally {
destroyed();
}
return rsList;
}
private List<Field> getFields(Class aClass) {
List<Field> fs = new ArrayList<>();
for (Field f : aClass.getDeclaredFields()) {
if (f.isAnnotationPresent(TableField.class)) {
fs.add(f);
}
}
return fs;
}
private <T> T[] concat(T[] arr1, T[] arr2) {
List<T> temp = new ArrayList<>();
temp.addAll(Arrays.asList(arr1));
temp.addAll(Arrays.asList(arr2));
return (T[]) temp.toArray();
}
}

@ -0,0 +1,94 @@
package xyz.wbsite.itchat4j.db;
import java.util.ArrayList;
import java.util.List;
public class Where {
private String sql;
private Object[] args;
private Where() {
}
public String getSql() {
return sql;
}
public void setSql(String sql) {
this.sql = sql;
}
public Object[] getArgs() {
return args;
}
public void setArgs(Object[] args) {
this.args = args;
}
public Where(String sql, Object[] args) {
this.sql = sql;
this.args = args;
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private StringBuilder sb = new StringBuilder();
private List<Object> argsList = new ArrayList<>();
public Builder eq(String name, Object value) {
return eq(true, name, value);
}
public Builder like(String name, Object value) {
return like(true, name, value);
}
public Builder isNull(String name, Object value) {
return isNull(true, name, value);
}
public Builder isNotNull(String name, Object value) {
return isNotNull(true, name, value);
}
public Builder eq(boolean condition, String name, Object value) {
if (condition) {
sb.append(sb.length() > 0 ? " and " : " where ").append(name).append(" = ? ");
argsList.add(value);
}
return this;
}
public Builder like(boolean condition, String name, Object value) {
if (condition) {
sb.append(sb.length() > 0 ? " and " : " where ").append(name).append("like ?");
argsList.add(value);
}
return this;
}
public Builder isNull(boolean condition, String name, Object value) {
if (condition) {
sb.append(sb.length() > 0 ? " and " : " where ").append(name).append("is null");
argsList.add(value);
}
return this;
}
public Builder isNotNull(boolean condition, String name, Object value) {
if (condition) {
sb.append(sb.length() > 0 ? " and " : " where ").append(name).append("is not null");
argsList.add(value);
}
return this;
}
public Where build() {
return new Where(sb.toString(), argsList.toArray());
}
}
}

@ -0,0 +1,13 @@
package xyz.wbsite.itchat4j.db.anonation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableField {
int value() default 20;
}

@ -0,0 +1,110 @@
package xyz.wbsite.itchat4j.db.entity;
import xyz.wbsite.itchat4j.db.anonation.TableField;
import java.util.Date;
public class Example {
@TableField(40)
private String s;
@TableField
private boolean b;
@TableField
private byte[] bs;
@TableField
private byte b1;
@TableField
private short s1;
@TableField
private int age;
@TableField
private long id;
@TableField
private float f1;
@TableField
private double d1;
@TableField
private Date date;
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
public boolean isB() {
return b;
}
public void setB(boolean b) {
this.b = b;
}
public byte[] getBs() {
return bs;
}
public void setBs(byte[] bs) {
this.bs = bs;
}
public byte getB1() {
return b1;
}
public void setB1(byte b1) {
this.b1 = b1;
}
public short getS1() {
return s1;
}
public void setS1(short s1) {
this.s1 = s1;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public float getF1() {
return f1;
}
public void setF1(float f1) {
this.f1 = f1;
}
public double getD1() {
return d1;
}
public void setD1(double d1) {
this.d1 = d1;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}

@ -0,0 +1,33 @@
package xyz.wbsite.itchat4j.ui;
import xyz.wbsite.itchat4j.util.ResourceUtil;
import javafx.fxml.FXMLLoader;
import java.io.IOException;
import java.net.URL;
/**
* FXML
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public class FXMLUtil {
/**
* FXMLLoader
*
* @param fxml
* @return
*/
public static FXMLLoader load(String fxml) throws IOException {
if (!fxml.startsWith("classpath:")) {
fxml = "classpath:" + fxml;
}
URL resource = ResourceUtil.getURL(fxml);
FXMLLoader fxmlLoader = new FXMLLoader(resource);
fxmlLoader.load();
return fxmlLoader;
}
}

@ -0,0 +1,269 @@
package xyz.wbsite.itchat4j.util;
import cn.hutool.core.util.ClassUtil;
import xyz.wbsite.itchat4j.JMainApplication;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBar;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.Tooltip;
import javafx.scene.image.Image;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.io.File;
import java.util.Optional;
import java.util.Timer;
import java.util.TimerTask;
public class DialogUtil {
private static Stage popup;
public static void toast(String msg, long time) {
Label label = new Label(msg);//默认信息
label.setStyle("-fx-background: rgba(56,56,56,0.7);-fx-border-radius: 25;-fx-background-radius: 25");//label透明,圆角
label.setTextFill(Color.rgb(225, 255, 226));//消息字体颜色
label.setPrefHeight(50);
label.setPadding(new Insets(15));
label.setAlignment(Pos.CENTER);//居中
label.setFont(new Font(20));//字体大小
Scene scene = new Scene(label);
scene.setFill(null);//场景透明
Stage stage = new Stage();
stage.initModality(Modality.WINDOW_MODAL);
stage.setAlwaysOnTop(false);
stage.setScene(scene);
label.setText(msg);
TimerTask task = new TimerTask() {
@Override
public void run() {
Platform.runLater(stage::close);
}
};
Timer timer = new Timer();
timer.schedule(task, time);
stage.show();
}
public static void showTimedDialog(final long time, String message) {
popup = new Stage();
popup.setAlwaysOnTop(true);
popup.initModality(Modality.APPLICATION_MODAL);
final Button closeBtn = new Button("知道了");
closeBtn.setOnAction(event -> popup.close());
VBox root = new VBox();
root.setPadding(new Insets(10));
root.setAlignment(Pos.BASELINE_CENTER);
root.setSpacing(10);
root.getChildren().addAll(new Label(message), closeBtn);
Scene scene = new Scene(root);
popup.setScene(scene);
popup.setTitle("提示信息");
popup.show();
Thread thread = new Thread(() -> {
try {
Thread.sleep(time);
if (popup.isShowing()) {
Platform.runLater(new Runnable() {
@Override
public void run() {
popup.close();
}
});
}
} catch (Exception exp) {
exp.printStackTrace();
}
});
thread.setDaemon(true);
thread.start();
}
public static void alert(String message) {
Platform.runLater(() -> {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
Stage stage = (Stage) alert.getDialogPane().getScene().getWindow();
stage.getIcons().add(new Image(ResourceUtil.getInput("icon.png")));
stage.setAlwaysOnTop(true);
alert.setHeaderText(null);
alert.setTitle("提示");
alert.setContentText(message);
alert.getButtonTypes().remove(ButtonType.CANCEL);
alert.setX(JMainApplication.primaryStage.getX() + JMainApplication.primaryStage.getWidth() / 2 - 213);
alert.setY(JMainApplication.primaryStage.getY() + JMainApplication.primaryStage.getHeight() / 2 - 70);
Optional<ButtonType> buttonType = alert.showAndWait();
});
}
public static void confirm(String message) {
confirm("提示", message, null);
}
public static void confirm(String title, String message) {
confirm(title, message, null);
}
public static void confirm(String title, String message, ConfirmCall call) {
Platform.runLater(() -> {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
Stage stage = (Stage) alert.getDialogPane().getScene().getWindow();
stage.getIcons().add(new Image(ResourceUtil.getInput("icon.png")));
stage.setAlwaysOnTop(true);
alert.setHeaderText(null);
alert.setTitle(title);
alert.setContentText(message);
alert.setX(JMainApplication.primaryStage.getX() + JMainApplication.primaryStage.getWidth() / 2 - 213);
alert.setY(JMainApplication.primaryStage.getY() + JMainApplication.primaryStage.getHeight() / 2 - 70);
Optional<ButtonType> buttonType = alert.showAndWait();
if (call != null) {
if (ButtonBar.ButtonData.OK_DONE.getTypeCode().equals(buttonType.get().getButtonData().getTypeCode())) {
call.call(true);
} else {
call.call(false);
}
}
});
}
public static void error(String message) {
Platform.runLater(() -> {
Alert alert = new Alert(Alert.AlertType.ERROR);
Stage stage = (Stage) alert.getDialogPane().getScene().getWindow();
stage.setAlwaysOnTop(true);
stage.getIcons().add(new Image(ResourceUtil.getInput("icon.png")));
alert.setTitle("错误");
alert.setX(JMainApplication.primaryStage.getX() + JMainApplication.primaryStage.getWidth() / 2 - 213);
alert.setY(JMainApplication.primaryStage.getY() + JMainApplication.primaryStage.getHeight() / 2 - 70);
alert.setHeaderText("");
alert.setContentText(message);
alert.show();
});
}
public static void success(String message) {
Platform.runLater(() -> {
Alert alert = new Alert(Alert.AlertType.INFORMATION);
Stage stage = (Stage) alert.getDialogPane().getScene().getWindow();
stage.getIcons().add(new Image(ResourceUtil.getInput("icon.png")));
alert.setTitle("消息");
alert.setX(JMainApplication.primaryStage.getX() + JMainApplication.primaryStage.getWidth() / 2 - 213);
alert.setY(JMainApplication.primaryStage.getY() + JMainApplication.primaryStage.getHeight() / 2 - 70);
alert.setHeaderText("");
alert.setContentText(message);
alert.show();
});
}
private static javafx.scene.control.Dialog dialog = null;
public static void loading(String message) {
loading(message, null);
}
public static void loading(String message, CancelCall cancelCall) {
if (dialog != null) return;
Platform.runLater(() -> {
dialog = new javafx.scene.control.Dialog();
dialog.setTitle("提示");
Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow();
stage.getIcons().add(new Image(ResourceUtil.getInput("icon.png")));
dialog.setResult("1");
dialog.setX(JMainApplication.primaryStage.getX() + JMainApplication.primaryStage.getWidth() / 2 - 68);
dialog.setY(JMainApplication.primaryStage.getY() + JMainApplication.primaryStage.getHeight() / 2 - 70);
GridPane gridPane = new GridPane();
gridPane.setPrefWidth(200);
gridPane.setHgap(10);
gridPane.setVgap(10);
gridPane.setAlignment(Pos.CENTER);
gridPane.setPadding(new Insets(10, 10, 10, 10));
dialog.getDialogPane().setContent(gridPane);
ProgressIndicator indicator = new ProgressIndicator();
indicator.setPrefSize(30, 30);
gridPane.add(indicator, 0, 0);
gridPane.add(new Label(message), 0, 1);
if (cancelCall != null) {
Button cancel = new Button("取消");
gridPane.add(cancel, 0, 2);
cancel.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
cancelCall.call();
}
});
}
dialog.show();
});
}
public static void hideLoading() {
if (dialog == null) return;
Platform.runLater(new Runnable() {
@Override
public void run() {
dialog.close();
dialog = null;
}
});
}
public interface InputCall {
void call(String input);
}
public interface ConfirmCall {
void call(boolean result);
}
public interface DirectoryCall {
void call(File result);
}
public interface CancelCall {
void call();
}
/**
*
*
* @param node
* @param tip
*/
public static void installTip(Node node, String tip) {
Tooltip tooltip = new Tooltip(tip);
try {
java.lang.reflect.Field behavior = ClassUtil.getDeclaredField(Tooltip.class, "BEHAVIOR");
behavior.setAccessible(true);
Object o = behavior.get(tooltip);
java.lang.reflect.Field activationTimer = ClassUtil.getDeclaredField(o.getClass(), "activationTimer");
activationTimer.setAccessible(true);
Timeline timeline = (Timeline) activationTimer.get(o);
timeline.getKeyFrames().remove(0);
timeline.getKeyFrames().add(new KeyFrame(new Duration(10)));
} catch (Exception ignored) {
}
Tooltip.install(node, tooltip);
}
}

@ -0,0 +1,107 @@
package xyz.wbsite.itchat4j.util;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.IoUtil;
import xyz.wbsite.itchat4j.JMainApplication;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public class ImageUtil {
private final static Map<String, BufferedImage> cache = new HashMap();
/**
*
*
* @param pic
* @return
*/
public static BufferedImage load(File pic) {
if (cache.containsKey(pic.getAbsolutePath())) {
return cache.get(pic.getAbsolutePath());
}
BufferedImage read = ImgUtil.read(pic);
cache.put(pic.getAbsolutePath(), read);
return read;
}
/**
*
*
* @param pics
* @return
*/
public static BufferedImage[] load(File[] pics) {
BufferedImage[] images = new BufferedImage[pics.length];
for (int i = 0; i < images.length; i++) {
images[i] = load(pics[i]);
}
return images;
}
/**
*
*
* @param pics
* @return
*/
public static List<BufferedImage> load(List<File> pics) {
List<BufferedImage> images = new ArrayList();
for (File file : pics) {
images.add(load(file));
}
return images;
}
public static int[][] getImageRGB(BufferedImage bfImage) {
int width = bfImage.getWidth();
int height = bfImage.getHeight();
int[][] result = new int[width][height];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// 对某个像素点的RGB编码并存入数据库
result[x][y] = bfImage.getRGB(x, y);
// 单独获取每一个像素点的Alpha, RedGreen和Blue的值。
// int a = rgb>>24 & 0xff;
// int r = rgb>>16 & 0xff;
// int g = rgb>>8 & 0xff;
// int b = rgb & 0xff;
}
}
return result;
}
/**
*
*
* @param image
*/
public static void show(BufferedImage image) {
Image showImage = image;
// 图片宽高都大于预览窗口时进行缩放显示
if (image.getWidth() > 192 || image.getHeight() > 108) {
// 宽高比大于预览窗口,适配宽, 否则适配高
if (1D * image.getWidth() / image.getHeight() > 192D / 108D) {
showImage = ImgUtil.scale(showImage, 1.0f * 192 / image.getWidth());
} else {
showImage = ImgUtil.scale(showImage, 1.0f * 108 / image.getHeight());
}
}
byte[] bytes = ImgUtil.toBytes(showImage, "PNG");
javafx.scene.image.Image image1 = new javafx.scene.image.Image(IoUtil.toStream(bytes));
JMainApplication.mainController.preview(image1);
}
}

@ -0,0 +1,52 @@
package xyz.wbsite.itchat4j.util;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.caller.CallerUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.level.Level;
import xyz.wbsite.itchat4j.JMainApplication;
/**
*
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public class Logger {
public static void info(String format, Object... arg) {
// 获取当前时间
DateTime date = DateUtil.date();
// 获取日志级别
String level = Level.INFO.toString();
// 格式化日志信息
String log = StrUtil.format(format, arg);
// 获取调用者类名
String name = CallerUtil.getCallerCaller().getSimpleName();
// 获取当前线程的堆栈追踪
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
// 通常堆栈追踪数组的第三个元素是logMessage方法的调用者
int lineNumber = stackTrace[2].getLineNumber();
// 打印日志信息
JMainApplication.mainController.println("[{}] [{}] {} [{}:{}]", date, level, log, name, lineNumber);
}
public static void error(String format, Object... arg) {
// 获取当前时间
DateTime date = DateUtil.date();
// 获取日志级别
String level = Level.ERROR.toString();
// 格式化日志信息
String log = StrUtil.format(format, arg);
// 获取调用者类名
String name = CallerUtil.getCallerCaller().getSimpleName();
// 获取当前线程的堆栈追踪
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
// 通常堆栈追踪数组的第三个元素是logMessage方法的调用者
int lineNumber = stackTrace[2].getLineNumber();
// 打印日志信息
JMainApplication.mainController.println("[{}] [{}] {} [{}:{}]", date, level, log, name, lineNumber);
}
}

@ -0,0 +1,62 @@
package xyz.wbsite.itchat4j.util;
import cn.hutool.core.io.resource.ClassPathResource;
import javafx.fxml.FXMLLoader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
/**
*
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public class ResourceUtil extends cn.hutool.core.io.resource.ResourceUtil {
/**
* ,/
*
* @return
*/
public static InputStream getInput(String resourceLocation) {
if (resourceLocation.startsWith("/")) {
resourceLocation = "/" + resourceLocation;
}
ClassPathResource classPathResource = new ClassPathResource(resourceLocation);
return classPathResource.getStream();
}
/**
*
*
* @param resourceLocation
*/
public static URL getURL(String resourceLocation) throws FileNotFoundException {
if (resourceLocation.startsWith("classpath:")) {
String path = resourceLocation.substring("classpath:".length());
ClassLoader cl = FXMLLoader.getDefaultClassLoader();
URL url = cl != null ? cl.getResource(path) : ClassLoader.getSystemResource(path);
if (url == null) {
String description = "class path resource [" + path + "]";
throw new FileNotFoundException(description + " cannot be resolved to URL because it does not exist");
} else {
return url;
}
} else {
try {
return new URL(resourceLocation);
} catch (MalformedURLException var6) {
try {
return (new File(resourceLocation)).toURI().toURL();
} catch (MalformedURLException var5) {
throw new FileNotFoundException("Resource location [" + resourceLocation + "] is neither a URL not a well-formed file path");
}
}
}
}
}

@ -0,0 +1,356 @@
package xyz.wbsite.itchat4j.util;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.cron.CronUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.*;
/**
* /
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public class TaskUtil extends CronUtil {
private static ScheduledExecutorService service;
public static ScheduledExecutorService getService() {
return service;
}
public static void setService(ScheduledExecutorService service) {
TaskUtil.service = service;
}
/**
* Runnable
*
* @param runnable Runnable
* @param delay (ms)
*/
public static ScheduledFuture<?> schedule(Runnable runnable, long delay, TimeUnit unit) {
if (service == null) {
service = new ScheduledThreadPoolExecutor(1);
}
return service.schedule(runnable, delay, unit);
}
/**
* Runnable
*
* @param callable Callable
* @param delay (ms)
*/
public static <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay) {
if (service == null) {
service = new ScheduledThreadPoolExecutor(1);
}
return service.schedule(callable, delay, TimeUnit.MILLISECONDS);
}
/**
* Runnable
*
* @param callable Callable
* @param delay
* @param unit
*/
public static <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
if (service == null) {
service = new ScheduledThreadPoolExecutor(1);
}
return service.schedule(callable, delay, unit);
}
/**
* Runnable
*
* @param runnable Runnable
* @param initialDelay
* @param period -
* @param unit
*/
public static ScheduledFuture<?> scheduleAtFixedRate(Runnable runnable, long initialDelay, long period, TimeUnit unit) {
if (service == null) {
service = new ScheduledThreadPoolExecutor(1);
}
return service.scheduleAtFixedRate(runnable, initialDelay, period, unit);
}
/**
* Runnable
*
* @param runnable Runnable
* @param initialDelay
* @param period -ms
*/
public static ScheduledFuture<?> scheduleAtFixedRate(Runnable runnable, long initialDelay, long period) {
if (service == null) {
service = new ScheduledThreadPoolExecutor(1);
}
return service.scheduleAtFixedRate(runnable, initialDelay, period, TimeUnit.MILLISECONDS);
}
/**
* Runnable
*
* @param runnable Runnable
* @param initialDelay
* @param delay -
* @param unit
*/
public static ScheduledFuture<?> scheduleWithFixedDelay(Runnable runnable, long initialDelay, long delay, TimeUnit unit) {
if (service == null) {
service = new ScheduledThreadPoolExecutor(1);
}
return service.scheduleAtFixedRate(runnable, initialDelay, delay, unit);
}
/**
* Runnable
*
* @param runnable Runnable
* @param initialDelay
* @param delay -ms
*/
public static ScheduledFuture<?> scheduleWithFixedDelay(Runnable runnable, long initialDelay, long delay) {
if (service == null) {
service = new ScheduledThreadPoolExecutor(1);
}
return service.scheduleAtFixedRate(runnable, initialDelay, delay, TimeUnit.MILLISECONDS);
}
public static void main(String[] args) {
TaskUtil.execTask(new Runnable() {
@Override
public void run() {
System.out.println("1");
}
}, 3, 3000);
}
/**
*
*
* @param runnable
* @param count
* @param interval
*/
public static void execTask(Runnable runnable, int count, long interval) {
for (int i = 0; i < count; i++) {
try {
runnable.run();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 控制重试时间间隔
if (i < count) {
ThreadUtil.sleep(interval);
}
}
}
}
/**
* IO
*
* @param runnable
* @param maxTryCount
* @param interval
* @param <T>
*/
public static <T> T retryTask(Callable<T> runnable, int maxTryCount, long interval) {
for (int i = 0; i < maxTryCount; i++) {
T t = null;
try {
t = runnable.call();
if (t != null) {
return t;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 控制重试时间间隔
if (t == null && i < maxTryCount - 1) {
ThreadUtil.sleep(interval);
}
}
}
return null;
}
public static <T> T retryTask(Callable<T> runnable) {
return retryTask(runnable, 3, 3000);
}
public static <T> T retryTask(Callable<T> runnable, int maxTryCount) {
return retryTask(runnable, maxTryCount, 3000);
}
/**
*
*
* @param callable
* @param time
*/
public static <T> T timeTask(Callable<T> callable, long time, TimeUnit unit) {
Future<T> submit = null;
try {
CompletionService<T> completionService = ThreadUtil.newCompletionService();
submit = completionService.submit(callable);
return submit.get(time, unit);
} catch (InterruptedException e) {
return null;
} catch (ExecutionException e) {
e.printStackTrace();
return null;
} catch (TimeoutException e) {
submit.cancel(true);
return null;
}
}
/**
*
*
* @param callable
* @param time
*/
public static void timeTask(Runnable callable, long time, TimeUnit unit) {
try {
CompletionService<Void> completionService = ThreadUtil.newCompletionService();
Future<Void> submit = completionService.submit(callable, null);
submit.get(time, unit);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
*/
public static void asyncTask(Runnable runnable) {
ThreadUtil.execAsync(runnable);
}
/**
*
*/
public static <T> Future<T> asyncTask(Callable<T> callables) {
return ThreadUtil.execAsync(callables);
}
/**
* 线
*/
public static void parallelTasks(Runnable... runnables) {
Assert.notEmpty(runnables, "callable can not empty");
CompletionService<Object> completionService = ThreadUtil.newCompletionService();
for (Runnable runnable : runnables) {
completionService.submit(runnable, null);
}
}
/**
* 线
*
*/
public static Object[] parallelTasks(Callable<Object>... callables) {
Assert.notEmpty(callables, "callable can not empty");
CompletionService<Object> completionService = ThreadUtil.newCompletionService();
Object[] result = new Object[callables.length];
List<Future> futures = new ArrayList<>();
for (Callable<Object> callable : callables) {
futures.add(completionService.submit(callable));
}
try {
for (int i = 0; i < result.length; i++) {
Future<Object> take = completionService.take();
int indexOf = futures.indexOf(take);
result[indexOf] = take.get();
System.out.println("result=" + result[indexOf]);
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* /.
*
*/
public static TaskStack flowTask(FlowTask task) {
return new TaskStack(task);
}
/**
* /
*/
public static class TaskStack {
private final Queue<FlowTask> taskFlowQueue = new ConcurrentLinkedQueue();
private final TaskEvent event = new TaskEvent() {
@Override
public void next(Object[] arg) {
FlowTask next = taskFlowQueue.poll();
if (next == null) {
return;
}
next.onTask(event, arg);
}
};
public TaskStack(FlowTask first) {
this.taskFlowQueue.add(first);
}
public void start(Object... arg) {
FlowTask first = this.taskFlowQueue.poll();
if (first == null) {
return;
}
first.onTask(event, arg);
}
public TaskStack then(FlowTask task) {
this.taskFlowQueue.add(task);
return this;
}
}
/**
* /
*/
public interface TaskEvent {
/**
*
*
* @param arg
*/
void next(Object... arg);
}
/**
*
*/
public interface FlowTask {
/**
*
*
* @param flow
* @param arg
*/
void onTask(TaskEvent flow, Object... arg);
}
}

@ -0,0 +1,45 @@
package xyz.wbsite.itchat4j.util;
/**
*
* <p>
*
*
* @author wangbing
* @version 0.0.1
* @since 1.8
*/
public class ValueUtil {
/**
*
*
* @param time 0~1
* @return 0~1
*/
public static double easeOut(double time) {
if (time <= 0) {
return 0D;
}
if (time >= 1) {
return 1D;
}
return Math.sin(time * Math.PI / 2);
}
/**
*
*
* @param time 0~1
* @return 0~1
*/
public static double easeIn(double time) {
if (time <= 0) {
return 0D;
}
if (time >= 1) {
return 1D;
}
return 1 - Math.cos(time * Math.PI / 2);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -0,0 +1,12 @@
/* styles.css */
.text-area,
.text-area:focused,
.text-area:unfocused,
.text-area:disabled {
-fx-control-inner-background: transparent;
-fx-background-color: transparent;
}
.text-area .content {
-fx-background-color: transparent;
}

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.geometry.Rectangle2D?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<AnchorPane prefHeight="300.0" prefWidth="600.0" stylesheets="@main.css" xmlns="http://javafx.com/javafx/17.0.2-ea"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="xyz.wbsite.itchat4j.JMainController">
<children>
<Separator layoutY="-1.0" opacity="0.5" prefWidth="200.0" AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"/>
<VBox maxWidth="204.0" minWidth="204.0" prefWidth="204.0" AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<HBox alignment="CENTER_LEFT" prefHeight="35.0" prefWidth="200.0">
<children>
<Button fx:id="start" focusTraversable="false" mnemonicParsing="false" onMouseClicked="#onStart"
prefHeight="30.0" prefWidth="100.0" text="开始(Ctrl+F1)"/>
<Button fx:id="stop" disable="true" focusTraversable="false" mnemonicParsing="false"
onMouseClicked="#onStop" prefHeight="30.0" prefWidth="100.0" text="停止(Ctrl+F2)">
<HBox.margin>
<Insets left="10.0"/>
</HBox.margin>
</Button>
</children>
<VBox.margin>
<Insets top="10.0"/>
</VBox.margin>
</HBox>
<!-- <HBox alignment="CENTER_LEFT">-->
<!-- <children>-->
<!-- <Label contentDisplay="CENTER" prefHeight="25.0" text="执行选项"/>-->
<!-- <ImageView fx:id="set" fitHeight="12.0" fitWidth="12.0" preserveRatio="true">-->
<!-- <HBox.margin>-->
<!-- <Insets left="5.0"/>-->
<!-- </HBox.margin>-->
<!-- <cursor>-->
<!-- <Cursor fx:constant="HAND"/>-->
<!-- </cursor>-->
<!-- </ImageView>-->
<!-- </children>-->
<!-- </HBox>-->
<!-- <HBox alignment="CENTER_LEFT" prefHeight="25.0" prefWidth="200.0">-->
<!-- <children>-->
<!-- <Label text="每"/>-->
<!-- <TextField fx:id="interval" alignment="CENTER" prefWidth="35.0" promptText="时间" text="60">-->
<!-- <HBox.margin>-->
<!-- <Insets left="3.0" right="3.0"/>-->
<!-- </HBox.margin>-->
<!-- </TextField>-->
<!-- <Label text="秒执行1次"/>-->
<!-- <Label text="共"/>-->
<!-- <TextField fx:id="times" alignment="CENTER" prefWidth="35.0" promptText="次数" text="1">-->
<!-- <HBox.margin>-->
<!-- <Insets left="3.0" right="3.0"/>-->
<!-- </HBox.margin>-->
<!-- </TextField>-->
<!-- <Label text="次"/>-->
<!-- </children>-->
<!-- </HBox>-->
<!-- <Label contentDisplay="CENTER" prefHeight="25.0" text="辅助工具"/>-->
<!-- <HBox alignment="CENTER_LEFT" prefHeight="35.0">-->
<!-- <children>-->
<!-- </children>-->
<!-- </HBox>-->
<Label prefHeight="25.0" prefWidth="204.0" text="登录二维码"/>
<AnchorPane maxHeight="192.0" maxWidth="192.0" minHeight="192.0" minWidth="192.0" prefHeight="192.0"
prefWidth="192.0" style="-fx-border-color: #ddd;">
<children>
<ImageView fx:id="preview" pickOnBounds="true" preserveRatio="true"
AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<viewport>
<Rectangle2D height="188.0" width="188.0"/>
</viewport>
</ImageView>
</children>
</AnchorPane>
<Label alignment="CENTER" contentDisplay="CENTER" prefHeight="35.0" prefWidth="188.0"
text="©2025 一团芝麻糊"/>
</children>
<padding>
<Insets left="6.0" right="6.0"/>
</padding>
</VBox>
<Separator opacity="0.5" orientation="VERTICAL" prefHeight="200.0" AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="204.0" AnchorPane.topAnchor="0.0"/>
<AnchorPane layoutX="262.0" layoutY="14.0" prefHeight="250.0" prefWidth="400.0" AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="204.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Label layoutY="4.0" prefHeight="30.0" prefWidth="60.0" text="控制台" AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<padding>
<Insets left="10.0" right="10.0"/>
</padding>
</Label>
<Separator layoutX="-3.0" layoutY="39.0" opacity="0.5" prefWidth="200.0" AnchorPane.leftAnchor="1.0"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="30.0"/>
<TextArea fx:id="console" editable="false" layoutX="1.0" layoutY="41.0" prefHeight="270.0"
style="-fx-background-color: transparent; -fx-focus-color: no; -fx-control-inner-background: transparent;-fx-text-fill: #444444;"
wrapText="true" AnchorPane.leftAnchor="1.0" AnchorPane.rightAnchor="0.0"
AnchorPane.topAnchor="35.0">
</TextArea>
</children>
</AnchorPane>
</children>
</AnchorPane>

@ -0,0 +1,33 @@
package cn.zhouyafeng.itchat4j.demo.demo1;
import cn.zhouyafeng.itchat4j.Wechat;
import cn.zhouyafeng.itchat4j.face.IMsgHandlerFace;
import java.io.File;
/**
*
* @author https://github.com/yaphone
* @date 2017428 12:44:10
* @version 1.0
*
*/
public class MyTest {
public static void main(String[] args) {
String qrPath = "D://itchat4j//login"; // 保存登陆二维码图片的路径,这里需要在本地新建目录
File folder = new File(qrPath);
if (!folder.exists()) {
boolean success = folder.mkdirs();
if (success) {
System.out.println("文件夹创建成功");
} else {
System.out.println("文件夹创建失败");
}
} else {
System.out.println("文件夹已存在");
}
IMsgHandlerFace msgHandler = new SimpleDemo(); // 实现IMsgHandlerFace接口的类
Wechat wechat = new Wechat(msgHandler, qrPath); // 【注入】
wechat.start(); // 启动服务会在qrPath下生成一张二维码图片扫描即可登陆注意二维码图片如果超过一定时间未扫描会过期过期时会自动更新所以你可能需要重新打开图片
}
}

@ -0,0 +1,108 @@
package cn.zhouyafeng.itchat4j.demo.demo1;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.log4j.Logger;
import cn.zhouyafeng.itchat4j.api.MessageTools;
import cn.zhouyafeng.itchat4j.api.WechatTools;
import cn.zhouyafeng.itchat4j.beans.BaseMsg;
import cn.zhouyafeng.itchat4j.beans.RecommendInfo;
import cn.zhouyafeng.itchat4j.core.Core;
import cn.zhouyafeng.itchat4j.face.IMsgHandlerFace;
import cn.zhouyafeng.itchat4j.utils.enums.MsgTypeEnum;
import cn.zhouyafeng.itchat4j.utils.tools.DownloadTools;
/**
*
*
* @author https://github.com/yaphone
* @date 2017425 12:18:09
* @version 1.0
*
*/
public class SimpleDemo implements IMsgHandlerFace {
Logger LOG = Logger.getLogger(SimpleDemo.class);
@Override
public String textMsgHandle(BaseMsg msg) {
// String docFilePath = "D:/itchat4j/pic/1.jpg"; // 这里是需要发送的文件的路径
if (!msg.isGroupMsg()) { // 群消息不处理
// String userId = msg.getString("FromUserName");
// MessageTools.sendFileMsgByUserId(userId, docFilePath); // 发送文件
// MessageTools.sendPicMsgByUserId(userId, docFilePath);
String text = msg.getText(); // 发送文本消息也可调用MessageTools.sendFileMsgByUserId(userId,text);
LOG.info(text);
if (text.equals("111")) {
WechatTools.logout();
}
if (text.equals("222")) {
WechatTools.remarkNameByNickName("yaphone", "Hello");
}
if (text.equals("333")) { // 测试群列表
System.out.print(WechatTools.getGroupNickNameList());
System.out.print(WechatTools.getGroupIdList());
System.out.print(Core.getInstance().getGroupMemeberMap());
}
return text;
}
return null;
}
@Override
public String picMsgHandle(BaseMsg msg) {
String fileName = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date());// 这里使用收到图片的时间作为文件名
String picPath = "D://itchat4j/pic" + File.separator + fileName + ".jpg"; // 调用此方法来保存图片
DownloadTools.getDownloadFn(msg, MsgTypeEnum.PIC.getType(), picPath); // 保存图片的路径
return "图片保存成功";
}
@Override
public String voiceMsgHandle(BaseMsg msg) {
String fileName = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date());
String voicePath = "D://itchat4j/voice" + File.separator + fileName + ".mp3";
DownloadTools.getDownloadFn(msg, MsgTypeEnum.VOICE.getType(), voicePath);
return "声音保存成功";
}
@Override
public String viedoMsgHandle(BaseMsg msg) {
String fileName = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date());
String viedoPath = "D://itchat4j/viedo" + File.separator + fileName + ".mp4";
DownloadTools.getDownloadFn(msg, MsgTypeEnum.VIEDO.getType(), viedoPath);
return "视频保存成功";
}
@Override
public String nameCardMsgHandle(BaseMsg msg) {
return "收到名片消息";
}
@Override
public void sysMsgHandle(BaseMsg msg) { // 收到系统消息
String text = msg.getContent();
LOG.info(text);
}
@Override
public String verifyAddFriendMsgHandle(BaseMsg msg) {
MessageTools.addFriend(msg, true); // 同意好友请求false为不接受好友请求
RecommendInfo recommendInfo = msg.getRecommendInfo();
String nickName = recommendInfo.getNickName();
String province = recommendInfo.getProvince();
String city = recommendInfo.getCity();
String text = "你好,来自" + province + city + "的" + nickName + " 欢迎添加我为好友!";
return text;
}
@Override
public String mediaMsgHandle(BaseMsg msg) {
String fileName = msg.getFileName();
String filePath = "D://itchat4j/file" + File.separator + fileName; // 这里是需要保存收到的文件路径文件可以是任何格式如PDFWORDEXCEL等。
DownloadTools.getDownloadFn(msg, MsgTypeEnum.MEDIA.getType(), filePath);
return "文件" + fileName + "保存成功";
}
}

@ -0,0 +1,111 @@
package cn.zhouyafeng.itchat4j.demo.demo2;
import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import org.apache.http.HttpEntity;
import org.apache.http.util.EntityUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import cn.zhouyafeng.itchat4j.Wechat;
import cn.zhouyafeng.itchat4j.beans.BaseMsg;
import cn.zhouyafeng.itchat4j.core.Core;
import cn.zhouyafeng.itchat4j.face.IMsgHandlerFace;
import cn.zhouyafeng.itchat4j.utils.MyHttpClient;
import cn.zhouyafeng.itchat4j.utils.enums.MsgTypeEnum;
import cn.zhouyafeng.itchat4j.utils.tools.DownloadTools;
/**
*
*
* @author https://github.com/yaphone
* @date 2017424 12:13:26
* @version 1.0
*
*/
public class TulingRobot implements IMsgHandlerFace {
Logger logger = Logger.getLogger("TulingRobot");
MyHttpClient myHttpClient = Core.getInstance().getMyHttpClient();
String url = "http://www.tuling123.com/openapi/api";
String apiKey = "597b34bea4ec4c85a775c469c84b6817"; // 这里是我申请的图灵机器人API接口每天只能5000次调用建议自己去申请一个免费的:)
@Override
public String textMsgHandle(BaseMsg msg) {
String result = "";
String text = msg.getText();
Map<String, String> paramMap = new HashMap<String, String>();
paramMap.put("key", apiKey);
paramMap.put("info", text);
paramMap.put("userid", "123456");
String paramStr = JSON.toJSONString(paramMap);
try {
HttpEntity entity = myHttpClient.doPost(url, paramStr);
result = EntityUtils.toString(entity, "UTF-8");
JSONObject obj = JSON.parseObject(result);
if (obj.getString("code").equals("100000")) {
result = obj.getString("text");
} else {
result = "处理有误";
}
} catch (Exception e) {
logger.info(e.getMessage());
}
return result;
}
@Override
public String picMsgHandle(BaseMsg msg) {
return "收到图片";
}
@Override
public String voiceMsgHandle(BaseMsg msg) {
String fileName = String.valueOf(new Date().getTime());
String voicePath = "D://itchat4j/voice" + File.separator + fileName + ".mp3";
DownloadTools.getDownloadFn(msg, MsgTypeEnum.VOICE.getType(), voicePath);
return "收到语音";
}
@Override
public String viedoMsgHandle(BaseMsg msg) {
String fileName = String.valueOf(new Date().getTime());
String viedoPath = "D://itchat4j/viedo" + File.separator + fileName + ".mp4";
DownloadTools.getDownloadFn(msg, MsgTypeEnum.VIEDO.getType(), viedoPath);
return "收到视频";
}
public static void main(String[] args) {
IMsgHandlerFace msgHandler = new TulingRobot();
Wechat wechat = new Wechat(msgHandler, "D://itchat4j/login");
wechat.start();
}
@Override
public String nameCardMsgHandle(BaseMsg msg) {
// TODO Auto-generated method stub
return null;
}
@Override
public void sysMsgHandle(BaseMsg msg) {
// TODO Auto-generated method stub
}
@Override
public String verifyAddFriendMsgHandle(BaseMsg msg) {
// TODO Auto-generated method stub
return null;
}
@Override
public String mediaMsgHandle(BaseMsg msg) {
// TODO Auto-generated method stub
return null;
}
}

@ -0,0 +1,120 @@
package cn.zhouyafeng.itchat4j.demo.demo3;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONObject;
import cn.zhouyafeng.itchat4j.Wechat;
import cn.zhouyafeng.itchat4j.api.WechatTools;
import cn.zhouyafeng.itchat4j.beans.BaseMsg;
import cn.zhouyafeng.itchat4j.core.Core;
import cn.zhouyafeng.itchat4j.face.IMsgHandlerFace;
import cn.zhouyafeng.itchat4j.utils.MyHttpClient;
import cn.zhouyafeng.itchat4j.utils.enums.StorageLoginInfoEnum;
/**
*
*
* @author https://github.com/yaphone
* @date 2017626 11:27:46
* @version 1.0
*
*/
public class PicYourFriends implements IMsgHandlerFace {
private static Logger LOG = LoggerFactory.getLogger(PicYourFriends.class);
private static final Core core = Core.getInstance();
private static final MyHttpClient myHttpClient = core.getMyHttpClient();
private static final String path = "D://itchat4j//head"; // 这里需要设置保存头像的路径
@Override
public String textMsgHandle(BaseMsg msg) {
if (!msg.isGroupMsg()) { // 群消息不处理
String text = msg.getText(); // 发送文本消息也可调用MessageTools.sendFileMsgByUserId(userId,text);
String baseUrl = "https://" + core.getIndexUrl(); // 基础URL
String skey = (String) core.getLoginInfo().get(StorageLoginInfoEnum.skey.getKey());
if (text.equals("111")) {
LOG.info("开始下载好友头像");
List<JSONObject> friends = WechatTools.getContactList();
for (int i = 0; i < friends.size(); i++) {
JSONObject friend = friends.get(i);
String url = baseUrl + friend.getString("HeadImgUrl") + skey;
// String fileName = friend.getString("NickName");
String headPicPath = path + File.separator + i + ".jpg";
HttpEntity entity = myHttpClient.doGet(url, null, true, null);
try {
OutputStream out = new FileOutputStream(headPicPath);
byte[] bytes = EntityUtils.toByteArray(entity);
out.write(bytes);
out.flush();
out.close();
} catch (Exception e) {
LOG.info(e.getMessage());
}
}
}
}
return null;
}
@Override
public String picMsgHandle(BaseMsg msg) {
// TODO Auto-generated method stub
return null;
}
@Override
public String voiceMsgHandle(BaseMsg msg) {
// TODO Auto-generated method stub
return null;
}
@Override
public String viedoMsgHandle(BaseMsg msg) {
// TODO Auto-generated method stub
return null;
}
@Override
public String nameCardMsgHandle(BaseMsg msg) {
// TODO Auto-generated method stub
return null;
}
@Override
public void sysMsgHandle(BaseMsg msg) {
// TODO Auto-generated method stub
}
public static void main(String[] args) {
String qrPath = "D://itchat4j//login"; // 保存登陆二维码图片的路径,这里需要在本地新建目录
IMsgHandlerFace msgHandler = new PicYourFriends(); // 实现IMsgHandlerFace接口的类
Wechat wechat = new Wechat(msgHandler, qrPath); // 【注入】
wechat.start(); // 启动服务会在qrPath下生成一张二维码图片扫描即可登陆注意二维码图片如果超过一定时间未扫描会过期过期时会自动更新所以你可能需要重新打开图片
}
@Override
public String verifyAddFriendMsgHandle(BaseMsg msg) {
// TODO Auto-generated method stub
return null;
}
@Override
public String mediaMsgHandle(BaseMsg msg) {
// TODO Auto-generated method stub
return null;
}
}

@ -0,0 +1,87 @@
package cn.zhouyafeng.itchat4j.demo.unuseful;
import java.io.IOException;
import cn.zhouyafeng.itchat4j.Wechat;
import cn.zhouyafeng.itchat4j.api.AssistTools;
import cn.zhouyafeng.itchat4j.beans.BaseMsg;
import cn.zhouyafeng.itchat4j.face.IMsgHandlerFace;
/**
*
*
* @author https://github.com/yaphone
* @date 2017522 10:41:44
* @version 1.0
*
*/
public class UnusefulDemo implements IMsgHandlerFace {
@Override
public String textMsgHandle(BaseMsg msg) {
if (!msg.isGroupMsg()) { // 群消息不处理
String text = msg.getText(); // 发送文本消息也可调用MessageTools.sendFileMsgByUserId(userId,text);
if (text.equals("111")) {
String username = "yaphone";
String password = "123456";
String localPath = "D://itchat4j/pic/1.jpg";
String uploadUrl = "http://127.0.0.1/file/put";
try {
AssistTools.sendQrPicToServer(username, password, uploadUrl, localPath);
} catch (IOException e) {
e.printStackTrace();
}
}
return text;
}
return null;
}
@Override
public String picMsgHandle(BaseMsg msg) {
// TODO Auto-generated method stub
return null;
}
@Override
public String voiceMsgHandle(BaseMsg msg) {
// TODO Auto-generated method stub
return null;
}
@Override
public String viedoMsgHandle(BaseMsg msg) {
// TODO Auto-generated method stub
return null;
}
@Override
public String nameCardMsgHandle(BaseMsg msg) {
// TODO Auto-generated method stub
return null;
}
public static void main(String[] args) {
IMsgHandlerFace msgHandler = new UnusefulDemo();
Wechat wechat = new Wechat(msgHandler, "D://itchat4j/login");
wechat.start();
}
@Override
public void sysMsgHandle(BaseMsg msg) {
// TODO Auto-generated method stub
}
@Override
public String verifyAddFriendMsgHandle(BaseMsg msg) {
// TODO Auto-generated method stub
return null;
}
@Override
public String mediaMsgHandle(BaseMsg msg) {
// TODO Auto-generated method stub
return null;
}
}
Loading…
Cancel
Save

Powered by TurnKey Linux.