diff --git a/README.md b/README.md index 7bf22f8..2ac4d6a 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ src/main/java是itchat4j的项目源码,在src/test/java目录下有两个小D ## 消息格式 -这里简要介绍一下`msg`各种消息,msg均为`json`格式的数据,可使用各自工具进行解析,在itchat4j中我通过alibaba的`fastjosn`工具库进行了解析,每种`msg`均为`fastjson`的标准`JSONObject`对象,后续处理起来非常方便,例如获取文本消息的消息内容:`msg.getString("Text")`,获取名片消息的被推荐人昵称:`msg.getJSONObject("RecommendInfo").getString("NickName")`。有时候可能不需要处理群消息,因此在构造`msg`消息体里我添加了一个判断是否群消息的字段`groupMsg`,可通过`msg.getBooleanValue("groupMsg")`获取字段的值,如果是群消息,返回true,如果非群消息,返回false。 +这里简要介绍一下`msg`各种消息,msg均为`json`格式的数据,可使用各自工具进行解析,在itchat4j中我通过alibaba的`fastjosn`工具库进行了解析,每种`msg`均为`fastjson`的标准`JSONObject`对象,后续处理起来非常方便,例如获取文本消息的消息内容:`msg.getString("Text")`,获取名片消息的被推荐人昵称:`msg.getJSONObject("RecommendInfo").getString("NickName")`。有时候可能不需要处理群消息,因此在构造`msg`消息体里我添加了一个判断是否群消息的字段`groupMsg`,可通过`msg.getBoolean("groupMsg")`获取字段的值,如果是群消息,返回true,如果非群消息,返回false。 ### 1.文本消息 @@ -458,43 +458,55 @@ public class MsgHandler implements IMsgHandlerFace { * 简单示例程序,收到文本信息自动回复原信息,收到图片、语音、小视频后根据路径自动保存 * * @author https://github.com/yaphone - * @date 创建时间:2017年4月28日 下午10:50:36 + * @date 创建时间:2017年4月25日 上午12:18:09 * @version 1.0 * */ public class SimpleDemo implements IMsgHandlerFace { + Logger LOG = Logger.getLogger(SimpleDemo.class); @Override public String textMsgHandle(JSONObject msg) { - String text = msg.getString("Text"); - return text; + String docFilePath = "D:/itchat4j/pic/test.docx"; // 这里是需要发送的文件的路径 + if (!msg.getBoolean("groupMsg")) { // 群消息不处理 + String userId = msg.getString("FromUserName"); + MessageTools.sendFileMsgByUserId(userId, docFilePath); // 发送文件 + String text = msg.getString("Text"); // 发送文本消息,也可调用MessageTools.sendFileMsgByUserId(userId,text); + return text; + } + return null; } @Override public String picMsgHandle(JSONObject msg) { - String fileName = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()) + ".jpg"; // 这里使用收到图片的时间作为文件名 - String picPath = "D://itchat4j/pic" + File.separator + fileName; // 保存图片的路径 - DownloadTools.getDownloadFn(msg, MsgType.PIC, picPath); // 调用此方法来保存图片 + 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(JSONObject msg) { - String fileName = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()) + ".mp3"; // 这里使用收到语音的时间作为文件名 - String voicePath = "D://itchat4j/voice" + File.separator + fileName; // 保存语音的路径 - DownloadTools.getDownloadFn(msg, MsgType.VOICE, voicePath); // 调用此方法来保存语音 + 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(JSONObject msg) { System.out.println(msg); - String fileName = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()) + ".mp4"; // 这里使用收到小视频的时间作为文件名 - String viedoPath = "D://itchat4j/viedo" + File.separator + fileName;// 保存小视频的路径 - DownloadTools.getDownloadFn(msg, MsgType.VIEDO, viedoPath);// 调用此方法来保存小视频 + 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(JSONObject msg) { + return "收到名片消息"; + } + } ``` @@ -510,7 +522,7 @@ public class SimpleDemo implements IMsgHandlerFace { * @version 1.0 * */ -public class Mytest { +public class MyTest { public static void main(String[] args) { String qrPath = "D://itchat4j//login"; // 保存登陆二维码图片的路径 IMsgHandlerFace msgHandler = new SimpleDemo(); // 实现IMsgHandlerFace接口的类 @@ -518,6 +530,7 @@ public class Mytest { wechat.start(); // 启动服务,会在qrPath下生成一张二维码图片,扫描即可登陆,注意,二维码图片如果超过一定时间未扫描会过期,过期时会自动更新,所以你可能需要重新打开图片 } } + ``` ### Demo2 图灵机器人 @@ -527,6 +540,7 @@ public class Mytest { 这个示例中我们接入图灵机器人的API,将收到的好友的文本信息发送给图灵机器人,并将机器人回复的消息发送给好友,接下来还是把舞台交代码和注释君吧。 ```Java + /** * 图灵机器人示例 * @@ -536,8 +550,7 @@ public class Mytest { * */ public class TulingRobot implements IMsgHandlerFace { - - MyHttpClient myHttpClient = new MyHttpClient(); + MyHttpClient myHttpClient = Core.getInstance().getMyHttpClient(); String apiKey = "597b34bea4ec4c85a775c469c84b6817"; // 这里是我申请的图灵机器人API接口,每天只能5000次调用,建议自己去申请一个,免费的:) Logger logger = Logger.getLogger("TulingRobot"); @@ -568,29 +581,39 @@ public class TulingRobot implements IMsgHandlerFace { @Override public String picMsgHandle(JSONObject msg) { - return "收到图片"; } @Override public String voiceMsgHandle(JSONObject 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(JSONObject 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, "/home/itchat4j/demo/itchat4j/login"); + Wechat wechat = new Wechat(msgHandler, "D://itchat4j/login"); wechat.start(); } + @Override + public String nameCardMsgHandle(JSONObject msg) { + // TODO Auto-generated method stub + return null; + } + } + ``` ### Demo3 itchat4j集成在SpringMVC应用中 diff --git a/logContentFile.log b/logContentFile.log new file mode 100644 index 0000000..e69de29 diff --git a/pom.xml b/pom.xml index afa0478..12430ed 100644 --- a/pom.xml +++ b/pom.xml @@ -16,13 +16,7 @@ - - junit - junit - 3.8.1 - test - - + org.apache.httpcomponents @@ -64,6 +58,31 @@ 1.1.1 + + + junit + junit + 4.12 + + + + + org.slf4j + slf4j-api + 1.6.6 + + + org.slf4j + slf4j-log4j12 + 1.6.6 + + + log4j + log4j + 1.2.16 + + + diff --git a/src/main/java/cn/zhouyafeng/itchat4j/Wechat.java b/src/main/java/cn/zhouyafeng/itchat4j/Wechat.java index f091066..baf4ee2 100644 --- a/src/main/java/cn/zhouyafeng/itchat4j/Wechat.java +++ b/src/main/java/cn/zhouyafeng/itchat4j/Wechat.java @@ -1,76 +1,31 @@ package cn.zhouyafeng.itchat4j; -import java.util.concurrent.TimeUnit; -import java.util.logging.Logger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import com.alibaba.fastjson.JSONObject; - -import cn.zhouyafeng.itchat4j.api.MessageTools; -import cn.zhouyafeng.itchat4j.components.Login; +import cn.zhouyafeng.itchat4j.controller.LoginController; +import cn.zhouyafeng.itchat4j.core.MsgCenter; import cn.zhouyafeng.itchat4j.face.IMsgHandlerFace; -import cn.zhouyafeng.itchat4j.utils.Core; -import cn.zhouyafeng.itchat4j.utils.MsgType; -/** - * 主类,初始化工作 - * - * @author https://github.com/yaphone - * @date 创建时间:2017年4月25日 上午12:42:54 - * @version 1.0 - * - */ public class Wechat { - private static Logger logger = Logger.getLogger("Wechat"); - private static Core core = Core.getInstance(); - + 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; - Login login = new Login(); - login.login(qrPath); - }; + // 登陆 + LoginController login = new LoginController(); + login.login(qrPath); + } public void start() { + LOG.info("+++++++++++++++++++开始消息处理+++++++++++++++++++++"); new Thread(new Runnable() { - @Override public void run() { - while (true) { - if (core.getMsgList().size() > 0 && core.getMsgList().get(0).getString("Content") != null) { - // System.out.println(core.getMsgList().get(0)); - if (core.getMsgList().get(0).getString("Content").length() > 0) { - JSONObject msg = core.getMsgList().get(0); - if (msg.getString("Type") != null) { - if (msg.getString("Type").equals(MsgType.TEXT)) { - String result = msgHandler.textMsgHandle(msg); - MessageTools.send(result, core.getMsgList().get(0).getString("FromUserName"), ""); - } else if (msg.getString("Type").equals(MsgType.PIC)) { - String result = msgHandler.picMsgHandle(msg); - MessageTools.send(result, core.getMsgList().get(0).getString("FromUserName"), ""); - } else if (msg.getString("Type").equals(MsgType.VOICE)) { - String result = msgHandler.voiceMsgHandle(msg); - MessageTools.send(result, core.getMsgList().get(0).getString("FromUserName"), ""); - } else if (msg.getString("Type").equals(MsgType.VIEDO)) { - String result = msgHandler.viedoMsgHandle(msg); - MessageTools.send(result, core.getMsgList().get(0).getString("FromUserName"), ""); - } else if (msg.getString("Type").equals(MsgType.NAMECARD)) { - String result = msgHandler.nameCardMsgHandle(msg); - MessageTools.send(result, core.getMsgList().get(0).getString("FromUserName"), ""); - } - } - } - core.getMsgList().remove(0); - } - try { - TimeUnit.MILLISECONDS.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } + MsgCenter.handleMsg(msgHandler); } }).start(); } diff --git a/src/main/java/cn/zhouyafeng/itchat4j/api/MessageTools.java b/src/main/java/cn/zhouyafeng/itchat4j/api/MessageTools.java index 2ea0a00..8cf126d 100644 --- a/src/main/java/cn/zhouyafeng/itchat4j/api/MessageTools.java +++ b/src/main/java/cn/zhouyafeng/itchat4j/api/MessageTools.java @@ -6,26 +6,25 @@ import java.util.HashMap; import java.util.Map; import java.util.Random; -import java.util.logging.Logger; -import java.util.regex.Matcher; import javax.activation.MimetypesFileTypeMap; +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.JSONArray; import com.alibaba.fastjson.JSONObject; -import cn.zhouyafeng.itchat4j.tools.CommonTool; -import cn.zhouyafeng.itchat4j.utils.Constant; -import cn.zhouyafeng.itchat4j.utils.Core; -import cn.zhouyafeng.itchat4j.utils.MsgType; +import cn.zhouyafeng.itchat4j.core.Core; +import cn.zhouyafeng.itchat4j.utils.Config; import cn.zhouyafeng.itchat4j.utils.MyHttpClient; +import cn.zhouyafeng.itchat4j.utils.enums.URLEnum; /** * 消息处理类 @@ -36,92 +35,10 @@ * */ public class MessageTools { - private static Logger logger = Logger.getLogger("Message"); + private static Logger LOG = LoggerFactory.getLogger(MessageTools.class); private static Core core = Core.getInstance(); private static MyHttpClient myHttpClient = core.getMyHttpClient(); - /** - * 接收消息,放入队列 - * - * @author https://github.com/yaphone - * @date 2017年4月23日 下午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("@@")) { // 群聊消息 - // produceGroupChat(core, m); - // m.remove("Content"); - 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及":
"消息,这里需要处理一下,去掉多余信息,只保留消息内容 - if (m.getString("Content").contains("
")) { - String content = m.getString("Content").substring(m.getString("Content").indexOf("
") + 5); - m.put("Content", content); - m.put("groupMsg", true); - } - } else { - CommonTool.msgFormatter(m, "Content"); - } - if (m.getInteger("MsgType") == MsgType.MSGTYPE_TEXT) { // words 文本消息 - if (m.getString("Url").length() != 0) { - String regEx = "(.+?\\(.+?\\))"; - Matcher matcher = CommonTool.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", MsgType.TEXT); - msg.put("Text", m.getString("Content")); - } - m.put("Type", msg.getString("Type")); - m.put("Text", msg.getString("Text")); - } else if (m.getInteger("MsgType") == MsgType.MSGTYPE_IMAGE - || m.getInteger("MsgType") == MsgType.MSGTYPE_EMOTICON) { // 图片消息 - m.put("Type", MsgType.PIC); - } else if (m.getInteger("MsgType") == MsgType.MSGTYPE_VOICE) { // 语音消息 - m.put("Type", MsgType.VOICE); - } else if (m.getInteger("MsgType") == 37) {// friends 好友确认消息 - - } else if (m.getInteger("MsgType") == 42) { // 共享名片 - m.put("Type", MsgType.NAMECARD); - - } else if (m.getInteger("MsgType") == MsgType.MSGTYPE_VIDEO - || m.getInteger("MsgType") == MsgType.MSGTYPE_MICROVIDEO) {// viedo - m.put("Type", MsgType.VIEDO); - } else if (m.getInteger("MsgType") == 49) { // sharing 分享链接 - - } else if (m.getInteger("MsgType") == 51) {// phone init 微信初始化消息 - - } else if (m.getInteger("MsgType") == 10000) {// 系统消息 - - } else if (m.getInteger("MsgType") == 10002) { // 撤回消息 - - } else { - logger.info("Useless msg"); - } - result.add(m); - } - return result; - } - - public static void send(String msg, String toUserName, String mediaId) { - sendMsg(msg, toUserName); - } - /** * 根据UserName发送文本消息 * @@ -130,9 +47,9 @@ public static void send(String msg, String toUserName, String mediaId) { * @param msg * @param toUserName */ - public static void sendMsg(String text, String toUserName) { - logger.info(String.format("Request to send a text message to %s: %s", toUserName, text)); - sendRawMsg(1, text, toUserName); + private static void sendMsg(String text, String toUserName) { + LOG.info(String.format("发送消息 %s: %s", toUserName, text)); + webWxSendMsg(1, text, toUserName); } /** @@ -159,7 +76,7 @@ public static boolean sendMsgByNickName(String text, String nickName) { if (nickName != null) { String toUserName = WechatTools.getUserNameByNickName(nickName); if (toUserName != null) { - sendRawMsg(1, text, toUserName); + webWxSendMsg(1, text, toUserName); return true; } } @@ -176,29 +93,24 @@ public static boolean sendMsgByNickName(String text, String nickName) { * @param content * @param toUserName */ - public static void sendRawMsg(int msgType, String content, String toUserName) { - String url = String.format("%s/webwxsendmsg", core.getLoginInfo().get("url")); - - Map paramMap = new HashMap(); - @SuppressWarnings("unchecked") - Map> baseRequestMap = (Map>) core.getLoginInfo() - .get("baseRequest"); - paramMap.put("BaseRequest", baseRequestMap.get("BaseRequest")); + 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 msgMap = new HashMap(); msgMap.put("Type", msgType); msgMap.put("Content", content); - msgMap.put("FromUserName", core.getStorageClass().getUserName()); - msgMap.put("ToUserName", toUserName == null ? core.getStorageClass().getUserName() : toUserName); + 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 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, "UTF-8"); + EntityUtils.toString(entity, Consts.UTF_8); } catch (Exception e) { - logger.info(e.getMessage()); + LOG.error("webWxSendMsg", e); } } @@ -219,13 +131,13 @@ public static void sendRawMsg(int msgType, String content, String toUserName) { * @param filePath * @return */ - private static JSONObject uploadMediaToServer(String filePath) { + private static JSONObject webWxUploadMedia(String filePath) { File f = new File(filePath); if (!f.exists() && f.isFile()) { - logger.info("file is not exist"); + LOG.info("file is not exist"); return null; } - String url = (String) core.getLoginInfo().get("fileUrl") + "/webwxuploadmedia?f=json"; + 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) { @@ -240,15 +152,12 @@ private static JSONObject uploadMediaToServer(String filePath) { + String.valueOf(new Random().nextLong()).substring(0, 4); String webwxDataTicket = MyHttpClient.getCookie("webwx_data_ticket"); if (webwxDataTicket == null) { - logger.info("get cookie webwx_data_ticket error"); + LOG.error("get cookie webwx_data_ticket error"); return null; } - Map paramMap = new HashMap(); - @SuppressWarnings("unchecked") - Map> baseRequestMap = (Map>) core.getLoginInfo() - .get("baseRequest"); - paramMap.put("BaseRequest", baseRequestMap.get("BaseRequest")); + Map paramMap = core.getParamMap(); + paramMap.put("ClientMediaId", clientMediaId); paramMap.put("TotalLen", fileSize); paramMap.put("StartPos", 0); @@ -272,10 +181,10 @@ private static JSONObject uploadMediaToServer(String filePath) { HttpEntity entity = myHttpClient.doPostFile(url, reqEntity); if (entity != null) { try { - String result = EntityUtils.toString(entity, "UTF-8"); + String result = EntityUtils.toString(entity, Consts.UTF_8); return JSON.parseObject(result); } catch (Exception e) { - logger.info(e.getMessage()); + LOG.error("webWxUploadMedia 错误: ", e); } } @@ -308,7 +217,7 @@ public static boolean sendPicMsgByNickName(String nickName, String filePath) { * @return */ public static boolean sendPicMsgByUserId(String userId, String filePath) { - JSONObject responseObj = uploadMediaToServer(filePath); + JSONObject responseObj = webWxUploadMedia(filePath); if (responseObj != null) { String mediaId = responseObj.getString("MediaId"); if (mediaId != null) { @@ -331,7 +240,7 @@ private static boolean webWxSendMsgImg(String userId, String mediaId) { Map msgMap = new HashMap(); msgMap.put("Type", 3); msgMap.put("MediaId", mediaId); - msgMap.put("FromUserName", core.getUserSelfList().get(0).getString("UserName")); + 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); @@ -347,10 +256,10 @@ private static boolean webWxSendMsgImg(String userId, String mediaId) { HttpEntity entity = myHttpClient.doPost(url, paramStr); if (entity != null) { try { - String result = EntityUtils.toString(entity, "UTF-8"); + String result = EntityUtils.toString(entity, Consts.UTF_8); return JSON.parseObject(result).getJSONObject("BaseResponse").getInteger("Ret") == 0; } catch (Exception e) { - logger.info(e.getMessage()); + LOG.error("webWxSendMsgImg 错误: ", e); } } return false; @@ -369,18 +278,18 @@ private static boolean webWxSendMsgImg(String userId, String mediaId) { public static boolean sendFileMsgByUserId(String userId, String filePath) { String title = new File(filePath).getName(); Map data = new HashMap(); - data.put("appid", Constant.API_WXAPPID); + 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 = uploadMediaToServer(filePath); + JSONObject responseObj = webWxUploadMedia(filePath); if (responseObj != null) { data.put("totallen", responseObj.getString("StartPos")); data.put("attachid", responseObj.getString("MediaId")); } else { - logger.info("sednFileMsgByUserId error"); + LOG.error("sednFileMsgByUserId 错误: ", data); } return webWxSendAppMsg(userId, data); } @@ -423,25 +332,30 @@ private static boolean webWxSendAppMsg(String userId, Map data) Map msgMap = new HashMap(); msgMap.put("Type", data.get("type")); msgMap.put("Content", content); - msgMap.put("FromUserName", core.getUserSelfList().get(0).getString("UserName")); + msgMap.put("FromUserName", core.getUserSelf().getString("UserName")); msgMap.put("ToUserName", userId); msgMap.put("LocalID", clientMsgId); msgMap.put("ClientMsgId", clientMsgId); - Map paramMap = new HashMap(); - @SuppressWarnings("unchecked") - Map> baseRequestMap = (Map>) core.getLoginInfo() - .get("baseRequest"); - paramMap.put("BaseRequest", baseRequestMap.get("BaseRequest")); + /* + * Map paramMap = new HashMap(); + * + * @SuppressWarnings("unchecked") Map> + * baseRequestMap = (Map>) + * core.getLoginInfo() .get("baseRequest"); paramMap.put("BaseRequest", + * baseRequestMap.get("BaseRequest")); + */ + + Map 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, "UTF-8"); + String result = EntityUtils.toString(entity, Consts.UTF_8); return JSON.parseObject(result).getJSONObject("BaseResponse").getInteger("Ret") == 0; } catch (Exception e) { - logger.info(e.getMessage()); + LOG.error("错误: ", e); } } return false; diff --git a/src/main/java/cn/zhouyafeng/itchat4j/api/WechatTools.java b/src/main/java/cn/zhouyafeng/itchat4j/api/WechatTools.java index 3061302..04db7e8 100644 --- a/src/main/java/cn/zhouyafeng/itchat4j/api/WechatTools.java +++ b/src/main/java/cn/zhouyafeng/itchat4j/api/WechatTools.java @@ -5,7 +5,7 @@ import com.alibaba.fastjson.JSONObject; -import cn.zhouyafeng.itchat4j.utils.Core; +import cn.zhouyafeng.itchat4j.core.Core; /** * 微信小工具,如获好友列表等 @@ -28,18 +28,7 @@ public class WechatTools { * @param toUserName */ public static void sendMsgByUserName(String msg, String toUserName) { - MessageTools.sendMsg(msg, toUserName); - } - - /** - * 获取好友列表,JSONObject格式 - * - * @author https://github.com/yaphone - * @date 2017年5月4日 下午10:55:18 - * @return - */ - private static List getJsonContactList() { - return core.getContactList(); + MessageTools.sendMsgById(msg, toUserName); } /** diff --git a/src/main/java/cn/zhouyafeng/itchat4j/components/Contact.java b/src/main/java/cn/zhouyafeng/itchat4j/components/Contact.java deleted file mode 100644 index 34615ef..0000000 --- a/src/main/java/cn/zhouyafeng/itchat4j/components/Contact.java +++ /dev/null @@ -1,12 +0,0 @@ -package cn.zhouyafeng.itchat4j.components; - -import com.alibaba.fastjson.JSONArray; - -import cn.zhouyafeng.itchat4j.utils.Core; - -public class Contact { - public static Object updateLocalChatrooms(Core core, JSONArray l) { - // TODO - return null; - } -} diff --git a/src/main/java/cn/zhouyafeng/itchat4j/components/Login.java b/src/main/java/cn/zhouyafeng/itchat4j/components/Login.java deleted file mode 100644 index 3e00a13..0000000 --- a/src/main/java/cn/zhouyafeng/itchat4j/components/Login.java +++ /dev/null @@ -1,555 +0,0 @@ -package cn.zhouyafeng.itchat4j.components; - -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.logging.Logger; -import java.util.regex.Matcher; - -import org.apache.http.HttpEntity; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.util.EntityUtils; -import org.w3c.dom.Document; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; - -import cn.zhouyafeng.itchat4j.api.MessageTools; -import cn.zhouyafeng.itchat4j.tools.CommonTool; -import cn.zhouyafeng.itchat4j.utils.Config; -import cn.zhouyafeng.itchat4j.utils.Contact; -import cn.zhouyafeng.itchat4j.utils.Core; -import cn.zhouyafeng.itchat4j.utils.MyHttpClient; - -public class Login { - private static Logger logger = Logger.getLogger("Wechat"); - private String baseUrl = Config.BASE_URL; - private boolean isLoginIn = false; - private Contact contact = new Contact(); - - private Core core = Core.getInstance(); - - private MyHttpClient myHttpClient = core.getMyHttpClient(); - - public Login() { - - } - - /** - * 登陆 - * - * @author https://github.com/yaphone - * @date 2017年5月5日 上午12:04:35 - * @param qrPath - * @return - */ - public int login(String qrPath) { - if (core.isAlive()) { // 已登陆 - logger.warning("itchat has already logged in."); - return 0; - } - while (true) { - for (int count = 0; count < 10; count++) { - logger.info("Getting uuid of QR code."); - while (getQRuuid() == null) { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - logger.info(e.getMessage()); - } - } - logger.info("Downloading QR code."); - Boolean qrStarge = getQR(qrPath); - if (qrStarge) { // 获取登陆二维码图片成功 - logger.info("Get QR success"); - break; - } else if (count == 10) { - logger.info("Failed to get QR code, please restart the program."); - System.exit(0); - } - } - logger.info("Please scan the QR code to log in."); - while (!isLoginIn) { - String status = checkLogin(); - if (status.equals("200")) { - isLoginIn = true; - logger.info(("登陆成功")); - } else if (status.equals("201")) { - logger.info("Please press confirm on your phone."); - isLoginIn = false; - } else { - break; - } - } - if (isLoginIn) - break; - logger.info("Log in time out, reloading QR code"); - } - this.webInit(); - this.showMobileLogin(); - contact.getContact(true); - CommonTool.clearScreen(); - logger.info(String.format("Login successfully as %s", core.getStorageClass().getNickName())); - startReceiving(); - webWxGetContact(); - return 0; - } - - /** - * 生成UUID - * - * @author https://github.com/yaphone - * @date 2017年4月11日 上午12:51:29 - * @return - */ - public String getQRuuid() { - String result = null; - String uuidUrl = baseUrl + "/jslogin"; - List params = new ArrayList(); - params.add(new BasicNameValuePair("appid", "wx782c26e4c19acffb")); - params.add(new BasicNameValuePair("fun", "new")); - HttpEntity entity = myHttpClient.doGet(uuidUrl, params, true, null); - try { - result = EntityUtils.toString(entity); - } catch (Exception e) { - logger.info(e.getMessage()); - } - String regEx = "window.QRLogin.code = (\\d+); window.QRLogin.uuid = \"(\\S+?)\";"; - Matcher matcher = CommonTool.getMatcher(regEx, result); - if (matcher.find()) { - if ((matcher.group(1).equals("200"))) { - core.setUuid(matcher.group(2));// - } - } - return core.getUuid(); - } - - /** - * 获取登陆二维码图片 - * - * @author https://github.com/yaphone - * @date 2017年4月20日 下午11:44:08 - * @return - */ - public boolean getQR(String qrPath) { - // String qrPath = Config.getLocalPath() + File.separator + "QR.jpg"; - qrPath = qrPath + File.separator + "QR.jpg"; - String qrUrl = baseUrl + "/qrcode/" + 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 { - CommonTool.printQr(qrPath); // 打开登陆二维码图片 - } catch (Exception e) { - logger.info(e.getMessage()); - } - - } catch (Exception e) { - logger.info(e.getMessage()); - return false; - } - - return true; - } - - /** - * 检查登陆状态 - * - * @author https://github.com/yaphone - * @date 2017年4月8日 下午11:22:16 - * @return - */ - public String checkLogin() { - String result = ""; - String checkUrl = baseUrl + "/cgi-bin/mmwebwx-bin/login"; - Long localTime = new Date().getTime(); - List params = new ArrayList(); - params.add(new BasicNameValuePair("loginicon", "true")); - params.add(new BasicNameValuePair("uuid", core.getUuid())); - params.add(new BasicNameValuePair("tip", "0")); - params.add(new BasicNameValuePair("r", String.valueOf(localTime / 1579L))); - params.add(new BasicNameValuePair("_", String.valueOf(localTime))); - HttpEntity entity = myHttpClient.doGet(checkUrl, params, true, null); - try { - result = EntityUtils.toString(entity); - } catch (Exception e) { - logger.info(e.getMessage()); - } - String regEx = "window.code=(\\d+)"; - Matcher matcher = CommonTool.getMatcher(regEx, result); - if (matcher.find()) { - if (matcher.group(1).equals("200")) { // 已登陆 - processLoginInfo(result); - return "200"; - } else if (matcher.group(1).equals("201")) { // 已扫描,未登陆 - return "201"; - } - } - return "400"; - } - - /** - * 处理登陆信息 - * - * @author https://github.com/yaphone - * @date 2017年4月9日 下午12:16:26 - * @param result - */ - public void processLoginInfo(String loginContent) { - String regEx = "window.redirect_uri=\"(\\S+)\";"; - Matcher matcher = CommonTool.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> possibleUrlMap = getPossibleUrlMap(); - Iterator>> iterator = possibleUrlMap.entrySet().iterator(); - Map.Entry> 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.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 text = ""; - // // 禁止重定向 - - try { - HttpEntity entity = myHttpClient.doGet(originalUrl, null, false, null); - text = EntityUtils.toString(entity); - } catch (Exception e) { - logger.info(e.getMessage()); - return; - } - Document doc = CommonTool.xmlParser(text); - Map> BaseRequest = new HashMap>(); - Map baseRequest = new HashMap(); - if (doc != null) { - core.getLoginInfo().put("skey", - doc.getElementsByTagName("skey").item(0).getFirstChild().getNodeValue()); - baseRequest.put("Skey", (String) core.getLoginInfo().get("skey")); - core.getLoginInfo().put("wxsid", - doc.getElementsByTagName("wxsid").item(0).getFirstChild().getNodeValue()); - baseRequest.put("Sid", (String) core.getLoginInfo().get("wxsid")); - core.getLoginInfo().put("wxuin", - doc.getElementsByTagName("wxuin").item(0).getFirstChild().getNodeValue()); - baseRequest.put("Uin", (String) core.getLoginInfo().get("wxuin")); - core.getLoginInfo().put("pass_ticket", - doc.getElementsByTagName("pass_ticket").item(0).getFirstChild().getNodeValue()); - baseRequest.put("DeviceID", (String) core.getLoginInfo().get("deviceid")); - BaseRequest.put("BaseRequest", baseRequest); - core.getLoginInfo().put("baseRequest", BaseRequest); - } - - } - } - - Map> getPossibleUrlMap() { - Map> possibleUrlMap = new HashMap>(); - possibleUrlMap.put("wx2.qq.com", new ArrayList() { - /** - * - */ - private static final long serialVersionUID = 1L; - - { - add("file.wx2.qq.com"); - add("webpush.wx2.qq.com"); - } - }); - possibleUrlMap.put("wx8.qq.com", new ArrayList() { - /** - * - */ - private static final long serialVersionUID = 1L; - - { - add("file.wx8.qq.com"); - add("webpush.wx8.qq.com"); - } - }); - - possibleUrlMap.put("web2.wechat.com", new ArrayList() { - /** - * - */ - private static final long serialVersionUID = 1L; - - { - add("file.web2.wechat.com"); - add("webpush.web2.wechat.com"); - } - }); - possibleUrlMap.put("wechat.com", new ArrayList() { - /** - * - */ - private static final long serialVersionUID = 1L; - - { - add("file.web.wechat.com"); - add("webpush.web.wechat.com"); - } - }); - return possibleUrlMap; - } - - private JSONObject webInit() { - JSONObject obj = null; - String url = core.getLoginInfo().get("url") + "/webwxinit?&r=" + String.valueOf(new Date().getTime()); - @SuppressWarnings("unchecked") - Map> paramMap = (Map>) core.getLoginInfo() - .get("baseRequest"); - String paramStr = JSON.toJSONString(paramMap); - try { - HttpEntity entity = myHttpClient.doPost(url, paramStr); - String result = EntityUtils.toString(entity, "UTF-8"); - obj = JSON.parseObject(result); - // TODO utils.emoji_formatter(dic['User'], 'NickName') - core.getLoginInfo().put("InviteStartCount", obj.getInteger("InviteStartCount")); - core.getLoginInfo().put("User", CommonTool.structFriendInfo(obj.getJSONObject("User"))); // 为userObj添加新字段 - core.getLoginInfo().put("SyncKey", obj.getJSONObject("SyncKey")); - JSONArray syncArray = obj.getJSONObject("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") + "|"); - } - String synckey = sb.toString(); - core.getLoginInfo().put("synckey", 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.getStorageClass().setUserName((obj.getJSONObject("User")).getString("UserName")); - core.getStorageClass().setNickName((obj.getJSONObject("User")).getString("NickName")); - core.getUserSelfList().add(obj.getJSONObject("User")); - } catch (Exception e) { - e.printStackTrace(); - } - return obj; - } - - private void showMobileLogin() { - String url = (String) core.getLoginInfo().get("url"); - String passTicket = (String) core.getLoginInfo().get("pass_ticket"); - String mobileUrl = String.format("%s/webwxstatusnotify?lang=zh_CN&pass_ticket=%s", url, passTicket); - Map paramMap = new HashMap(); - @SuppressWarnings("unchecked") - Map> baseRequestMap = (Map>) core.getLoginInfo() - .get("baseRequest"); - paramMap.put("BaseRequest", baseRequestMap.get("BaseRequest")); - paramMap.put("Code", 3); - paramMap.put("FromUserName", core.getStorageClass().getUserName()); - paramMap.put("ToUserName", core.getStorageClass().getUserName()); - paramMap.put("ClientMsgId", String.valueOf(new Date().getTime())); - String paramStr = JSON.toJSONString(paramMap); - try { - HttpEntity entity = myHttpClient.doPost(mobileUrl, paramStr); - EntityUtils.toString(entity, "UTF-8"); - } catch (Exception e) { - - } - } - - void startReceiving() { - core.setAlive(true); - new Thread(new Runnable() { - int retryCount = 0; - - @Override - public void run() { - while (core.isAlive()) { - try { - String i = syncCheck(); - if (i == null) { - core.setAlive(false); - } else if (i.equals("0")) { - continue; - } else { - JSONArray msgList = new JSONArray(); - JSONObject msgObj = getMsg(); - if (msgObj != null) { - msgList = msgObj.getJSONArray("AddMsgList"); - msgList = MessageTools.produceMsg(msgList); - for (int j = 0; j < msgList.size(); j++) { - core.getMsgList().add(msgList.getJSONObject(j)); - } - - // TODO chatroomMsg = - // update_local_chatrooms(self, chatroomList) - // TODO self.msgList.put(chatroomMsg) - // TODO update_local_friends(self, otherList) - } - } - retryCount = 0; - - } catch (Exception e) { - logger.info(e.getMessage()); - retryCount += 1; - if (core.getReceivingRetryCount() < retryCount) { - core.setAlive(false); - } else { - try { - Thread.sleep(1000); - } catch (InterruptedException e1) { - logger.info(e.getMessage()); - } - } - } - - } - } - }).start(); - } - - /** - * 保活心跳 - * - * @author https://github.com/yaphone - * @date 2017年4月16日 上午11:11:34 - * @return - */ - String syncCheck() { - String result = null; - String syncUrl = (String) core.getLoginInfo().get("syncUrl"); - // String syncUrl = "https://webpush.wx2.qq.com/cgi-bin/mmwebwx-bin"; - if (syncUrl == null || syncUrl.equals("")) { - syncUrl = (String) core.getLoginInfo().get("url"); - } - String url = String.format("%s/synccheck", syncUrl); - List params = new ArrayList(); - params.add(new BasicNameValuePair("r", String.valueOf(new Date().getTime()))); - params.add(new BasicNameValuePair("skey", (String) core.getLoginInfo().get("skey"))); - params.add(new BasicNameValuePair("sid", (String) core.getLoginInfo().get("wxsid"))); - params.add(new BasicNameValuePair("uin", (String) core.getLoginInfo().get("wxuin"))); - params.add(new BasicNameValuePair("deviceid", (String) core.getLoginInfo().get("deviceid"))); - params.add(new BasicNameValuePair("synckey", (String) core.getLoginInfo().get("synckey"))); - params.add(new BasicNameValuePair("_", String.valueOf(new Date().getTime()))); - try { - HttpEntity entity = myHttpClient.doGet(url, params, true, null); - if (entity == null) { - return "0"; - } - String text = EntityUtils.toString(entity); - String regEx = "window.synccheck=\\{retcode:\"(\\d+)\",selector:\"(\\d+)\"\\}"; - Matcher matcher = CommonTool.getMatcher(regEx, text); - if (!matcher.find() || matcher.group(1).equals("2")) { - logger.info(String.format("Unexpected sync check result: %s", text)); - } else { - result = matcher.group(2); - } - } catch (Exception e) { - e.printStackTrace(); - } - return result; - } - - JSONObject getMsg() { - JSONObject result = new JSONObject(); - String url = String.format("%s/webwxsync?sid=%s&skey=%s&pass_ticket=%s", core.getLoginInfo().get("url"), - core.getLoginInfo().get("wxsid"), core.getLoginInfo().get("skey"), - core.getLoginInfo().get("pass_ticket")); - Map paramMap = new HashMap(); - @SuppressWarnings("unchecked") - Map> baseRequestMap = (Map>) core.getLoginInfo() - .get("baseRequest"); - paramMap.put("BaseRequest", baseRequestMap.get("BaseRequest")); - paramMap.put("SyncKey", core.getLoginInfo().get("SyncKey")); - paramMap.put("rr", -new Date().getTime() / 1000); - String paramStr = JSON.toJSONString(paramMap); - try { - HttpEntity entity = myHttpClient.doPost(url, paramStr); - String text = EntityUtils.toString(entity, "UTF-8"); - JSONObject obj = JSON.parseObject(text); - if (obj.getJSONObject("BaseResponse").getInteger("Ret") != 0) { - result = null; - } else { - result = obj; - core.getLoginInfo().put("SyncKey", obj.getJSONObject("SyncCheckKey")); - JSONArray syncArray = obj.getJSONObject("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") + "|"); - } - String synckey = sb.toString(); - core.getLoginInfo().put("synckey", 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) { - logger.info(e.getMessage()); - } - return result; - - } - - /** - *

- * 获取联系人信息,成功返回true,失败返回false - *

- *

- * get all contacts: people, group, public user, special user - *

- * - * @author https://github.com/yaphone - * @date 2017年5月3日 上午12:28:51 - * @return - */ - boolean webWxGetContact() { - String result = ""; - String url = String.format("%s/webwxgetcontact", core.getLoginInfo().get("url")); - List params = new ArrayList(); - params.add(new BasicNameValuePair("pass_ticket", (String) core.getLoginInfo().get("pass_ticket"))); - params.add(new BasicNameValuePair("skey", (String) core.getLoginInfo().get("skey"))); - params.add(new BasicNameValuePair("r", String.valueOf(String.valueOf(new Date().getTime())))); - HttpEntity entity = myHttpClient.doGet(url, params, true, null); - try { - result = EntityUtils.toString(entity, "UTF-8"); - } catch (Exception e) { - logger.info(e.getMessage()); - } - JSONObject fullFriendsJsonList = JSON.parseObject(result); - core.setMemberCount(fullFriendsJsonList.getInteger(("MemberCount"))); - JSONArray memberJsonArray = fullFriendsJsonList.getJSONArray("MemberList"); - for (int i = 0; i < memberJsonArray.size(); i++) { - core.getMemberList().add(memberJsonArray.getJSONObject(i)); - } - for (JSONObject o : core.getMemberList()) { - 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) { // 群聊 - core.getGroupList().add(o); - } else if (o.getString("UserName").equals(core.getUserSelfList().get(0).getString("UserName"))) { // 自己 - core.getContactList().remove(o); - } else { // 普通联系人 - core.getContactList().add(o); - } - } - return true; - } - -} diff --git a/src/main/java/cn/zhouyafeng/itchat4j/controller/LoginController.java b/src/main/java/cn/zhouyafeng/itchat4j/controller/LoginController.java new file mode 100644 index 0000000..2d5fce9 --- /dev/null +++ b/src/main/java/cn/zhouyafeng/itchat4j/controller/LoginController.java @@ -0,0 +1,77 @@ +package cn.zhouyafeng.itchat4j.controller; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import cn.zhouyafeng.itchat4j.core.Core; +import cn.zhouyafeng.itchat4j.service.ILoginService; +import cn.zhouyafeng.itchat4j.service.impl.LoginServiceImpl; +import cn.zhouyafeng.itchat4j.utils.SleepUtils; +import cn.zhouyafeng.itchat4j.utils.tools.CommonTools; + +/** + * 登陆控制器 + * + * @author https://github.com/yaphone + * @date 创建时间:2017年5月13日 下午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("6. 清除。。。。"); + CommonTools.clearScreen(); + LOG.info(String.format("欢迎回来, %s", core.getNickName())); + + LOG.info("7. 开始接收消息"); + loginService.startReceiving(); + + LOG.info("8. 获取联系人信息"); + loginService.webWxGetContact(); + } +} \ No newline at end of file diff --git a/src/main/java/cn/zhouyafeng/itchat4j/utils/Core.java b/src/main/java/cn/zhouyafeng/itchat4j/core/Core.java similarity index 66% rename from src/main/java/cn/zhouyafeng/itchat4j/utils/Core.java rename to src/main/java/cn/zhouyafeng/itchat4j/core/Core.java index e0a0c03..b428f12 100644 --- a/src/main/java/cn/zhouyafeng/itchat4j/utils/Core.java +++ b/src/main/java/cn/zhouyafeng/itchat4j/core/Core.java @@ -1,4 +1,4 @@ -package cn.zhouyafeng.itchat4j.utils; +package cn.zhouyafeng.itchat4j.core; import java.util.ArrayList; import java.util.HashMap; @@ -7,6 +7,9 @@ import com.alibaba.fastjson.JSONObject; +import cn.zhouyafeng.itchat4j.utils.MyHttpClient; +import cn.zhouyafeng.itchat4j.utils.enums.parameters.BaseParaEnum; + /** * 核心存储类,全局只保存一份,单例模式 * @@ -33,37 +36,50 @@ public static Core getInstance() { } boolean alive = false; - Storage storageClass = Storage.getInstance(); private int memberCount = 0; - private List userSelfList = storageClass.getUserSelfList(); - private List memberList = storageClass.getMemberList(); - private List contactList = storageClass.getContactList(); - private List groupList = storageClass.getGroupList(); - private List groupMemeberList = storageClass.getGroupList(); - private List publicUsersList = storageClass.getPublicUsersList(); - private List specialUsersList = storageClass.getSpecialUsersList(); - private List msgList = storageClass.getMsgList(); + private String userName; + private String nickName; + private List msgList = new ArrayList(); - private List groupIdList = new ArrayList(); // 群聊,以String格式保存群的userName,如@@37da24fee2114e9475729b942d130190ffddb669411228651da3e8a8933603c8 + private JSONObject userSelf; // 登陆账号自身信息 + private List memberList = new ArrayList(); // 好友+群聊+公众号+特殊账号 + private List contactList = new ArrayList();;// 好友 + private List groupList = new ArrayList();; // 群 + private List groupMemeberList = new ArrayList();; // 群聊成员字典 + private List publicUsersList = new ArrayList();;// 公众号/服务号 + private List specialUsersList = new ArrayList();;// 特殊账号 + private List groupIdList = new ArrayList(); Map loginInfo = new HashMap(); // CloseableHttpClient httpClient = HttpClients.createDefault(); MyHttpClient myHttpClient = MyHttpClient.getInstance(); String uuid = null; - Map functionDict = new HashMap() { - { - put("FriendChat", new HashMap()); - put("GroupChat", new HashMap()); - put("MpChat", new HashMap()); - } - }; - boolean useHotReload = false; String hotReloadDir = "itchat.pkl"; int receivingRetryCount = 5; + /** + * 请求参数 + */ + public Map getParamMap() { + return new HashMap(1) { + /** + * + */ + private static final long serialVersionUID = 1L; + + { + Map map = new HashMap(); + for (BaseParaEnum baseRequest : BaseParaEnum.values()) { + map.put(baseRequest.para(), getLoginInfo().get(baseRequest.value()).toString()); + } + put("BaseRequest", map); + } + }; + } + public boolean isAlive() { return alive; } @@ -72,14 +88,6 @@ public void setAlive(boolean alive) { this.alive = alive; } - public Storage getStorageClass() { - return storageClass; - } - - public void setStorageClass(Storage storageClass) { - this.storageClass = storageClass; - } - public List getMemberList() { return memberList; } @@ -104,10 +112,6 @@ public void setUuid(String uuid) { this.uuid = uuid; } - public Map getFunctionDict() { - return functionDict; - } - public int getMemberCount() { return memberCount; } @@ -116,10 +120,6 @@ public void setMemberCount(int memberCount) { this.memberCount = memberCount; } - public void setFunctionDict(Map functionDict) { - this.functionDict = functionDict; - } - public boolean isUseHotReload() { return useHotReload; } @@ -168,14 +168,6 @@ public void setGroupIdList(List groupIdList) { this.groupIdList = groupIdList; } - public List getUserSelfList() { - return userSelfList; - } - - public void setUserSelfList(List userSelfList) { - this.userSelfList = userSelfList; - } - public List getContactList() { return contactList; } @@ -216,4 +208,28 @@ public void setSpecialUsersList(List 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; + } + } diff --git a/src/main/java/cn/zhouyafeng/itchat4j/core/MsgCenter.java b/src/main/java/cn/zhouyafeng/itchat4j/core/MsgCenter.java new file mode 100644 index 0000000..d97b338 --- /dev/null +++ b/src/main/java/cn/zhouyafeng/itchat4j/core/MsgCenter.java @@ -0,0 +1,154 @@ +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.face.IMsgHandlerFace; +import cn.zhouyafeng.itchat4j.utils.MsgCodeEnum; +import cn.zhouyafeng.itchat4j.utils.enums.MsgTypeEnum; +import cn.zhouyafeng.itchat4j.utils.tools.CommonTools; + +/** + * 消息处理中心 + * + * @author https://github.com/yaphone + * @date 创建时间:2017年5月14日 下午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 2017年4月23日 下午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及":
"消息,这里需要处理一下,去掉多余信息,只保留消息内容 + if (m.getString("Content").contains("
")) { + String content = m.getString("Content").substring(m.getString("Content").indexOf("
") + 5); + m.put("Content", content); + m.put("groupMsg", true); + } + } else { + CommonTools.msgFormatter(m, "Content"); + } + if (m.getInteger("MsgType") == 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") == MsgCodeEnum.MSGTYPE_IMAGE.getCode() + || m.getInteger("MsgType") == MsgCodeEnum.MSGTYPE_EMOTICON.getCode()) { // 图片消息 + m.put("Type", MsgTypeEnum.PIC.getType()); + } else if (m.getInteger("MsgType") == MsgCodeEnum.MSGTYPE_VOICE.getCode()) { // 语音消息 + m.put("Type", MsgTypeEnum.VOICE.getType()); + } else if (m.getInteger("MsgType") == MsgCodeEnum.MSGTYPE_VERIFYMSG.getCode()) {// friends + // 好友确认消息 + + } else if (m.getInteger("MsgType") == MsgCodeEnum.MSGTYPE_SHARECARD.getCode()) { // 共享名片 + m.put("Type", MsgTypeEnum.NAMECARD.getType()); + + } else if (m.getInteger("MsgType") == MsgCodeEnum.MSGTYPE_VIDEO.getCode() + || m.getInteger("MsgType") == MsgCodeEnum.MSGTYPE_MICROVIDEO.getCode()) {// viedo + m.put("Type", MsgTypeEnum.VIEDO.getType()); + } else if (m.getInteger("MsgType") == MsgCodeEnum.MSGTYPE_APP.getCode()) { // sharing + // 分享链接 + + } else if (m.getInteger("MsgType") == MsgCodeEnum.MSGTYPE_STATUSNOTIFY.getCode()) {// phone + // init + // 微信初始化消息 + + } else if (m.getInteger("MsgType") == MsgCodeEnum.MSGTYPE_SYS.getCode()) {// 系统消息 + + } else if (m.getInteger("MsgType") == 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 2017年5月14日 上午10:52:34 + * @param msgHandler + */ + public static void handleMsg(IMsgHandlerFace msgHandler) { + while (true) { + if (core.getMsgList().size() > 0 && core.getMsgList().get(0).getString("Content") != null) { + if (core.getMsgList().get(0).getString("Content").length() > 0) { + JSONObject msg = core.getMsgList().get(0); + if (msg.getString("Type") != null) { + if (msg.getString("Type").equals(MsgTypeEnum.TEXT.getType())) { + String result = msgHandler.textMsgHandle(msg); + MessageTools.sendMsgById(result, core.getMsgList().get(0).getString("FromUserName")); + } else if (msg.getString("Type").equals(MsgTypeEnum.PIC.getType())) { + String result = msgHandler.picMsgHandle(msg); + MessageTools.sendMsgById(result, core.getMsgList().get(0).getString("FromUserName")); + } else if (msg.getString("Type").equals(MsgTypeEnum.VOICE.getType())) { + String result = msgHandler.voiceMsgHandle(msg); + MessageTools.sendMsgById(result, core.getMsgList().get(0).getString("FromUserName")); + } else if (msg.getString("Type").equals(MsgTypeEnum.VIEDO.getType())) { + String result = msgHandler.viedoMsgHandle(msg); + MessageTools.sendMsgById(result, core.getMsgList().get(0).getString("FromUserName")); + } else if (msg.getString("Type").equals(MsgTypeEnum.NAMECARD.getType())) { + String result = msgHandler.nameCardMsgHandle(msg); + MessageTools.sendMsgById(result, core.getMsgList().get(0).getString("FromUserName")); + } + } + } + core.getMsgList().remove(0); + } + try { + TimeUnit.MILLISECONDS.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + +} diff --git a/src/main/java/cn/zhouyafeng/itchat4j/service/ILoginService.java b/src/main/java/cn/zhouyafeng/itchat4j/service/ILoginService.java new file mode 100644 index 0000000..349ecf3 --- /dev/null +++ b/src/main/java/cn/zhouyafeng/itchat4j/service/ILoginService.java @@ -0,0 +1,75 @@ +package cn.zhouyafeng.itchat4j.service; + +/** + * 登陆服务接口 + * + * @author https://github.com/yaphone + * @date 创建时间:2017年5月13日 上午12:07:21 + * @version 1.0 + * + */ +public interface ILoginService { + + /** + * 登陆 + * + * @author https://github.com/yaphone + * @date 2017年5月13日 上午12:14:07 + * @return + */ + boolean login(); + + /** + * 获取UUID + * + * @author https://github.com/yaphone + * @date 2017年5月13日 上午12:21:40 + * @param qrPath + * @return + */ + String getUuid(); + + /** + * 获取二维码图片 + * + * @author https://github.com/yaphone + * @date 2017年5月13日 上午12:13:51 + * @param qrPath + * @return + */ + boolean getQR(String qrPath); + + /** + * web初始化 + * + * @author https://github.com/yaphone + * @date 2017年5月13日 上午12:14:13 + * @return + */ + boolean webWxInit(); + + /** + * 微信状态通知 + * + * @author https://github.com/yaphone + * @date 2017年5月13日 上午12:14:24 + */ + void wxStatusNotify(); + + /** + * 接收消息 + * + * @author https://github.com/yaphone + * @date 2017年5月13日 上午12:14:37 + */ + void startReceiving(); + + /** + * 获取微信联系人 + * + * @author https://github.com/yaphone + * @date 2017年5月13日 下午2:26:18 + */ + void webWxGetContact(); + +} diff --git a/src/main/java/cn/zhouyafeng/itchat4j/service/impl/LoginServiceImpl.java b/src/main/java/cn/zhouyafeng/itchat4j/service/impl/LoginServiceImpl.java new file mode 100644 index 0000000..af061a0 --- /dev/null +++ b/src/main/java/cn/zhouyafeng/itchat4j/service/impl/LoginServiceImpl.java @@ -0,0 +1,547 @@ +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.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 创建时间:2017年5月13日 上午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 params = new ArrayList(); + 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 params = new ArrayList(); + 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() { + // 组装请求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 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")); + return true; + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + + @Override + public void wxStatusNotify() { + // 组装请求URL和参数 + String url = String.format(URLEnum.STATUS_NOTIFY_URL.getUrl(), + core.getLoginInfo().get(StorageLoginInfoEnum.pass_ticket.getKey())); + + Map 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 resultMap = syncCheck(); + 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())) { + if (selector.equals("2")) { + JSONObject msgObj = webWxSync(); + if (msgObj != null) { + try { + JSONArray msgList = new JSONArray(); + msgList = msgObj.getJSONArray("AddMsgList"); + msgList = MsgCenter.produceMsg(msgList); + for (int j = 0; j < msgList.size(); j++) { + core.getMsgList().add(msgList.getJSONObject(j)); + } + } catch (Exception e) { + LOG.info(e.getMessage()); + } + } else if (selector.equals("7")) { + webWxSync(); + } else if (selector.equals("4")) { + // 保存群聊到通讯录 + // 修改群名称 + // 新增或删除联系人 + // 群聊成员数目变化 + // TODO + } else if (selector.equals("3") || selector.equals("6")) { + break; + } + } + } 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 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); + + core.setMemberCount(fullFriendsJsonList.getInteger(StorageLoginInfoEnum.MemberCount.getKey())); + JSONArray member = fullFriendsJsonList.getJSONArray(StorageLoginInfoEnum.MemberList.getKey()); + 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) { // 群聊 + 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; + } + + /** + * 检查登陆状态 + * + * @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 2017年4月9日 下午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> possibleUrlMap = this.getPossibleUrlMap(); + Iterator>> iterator = possibleUrlMap.entrySet().iterator(); + Map.Entry> 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.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 text = ""; + + try { + HttpEntity entity = myHttpClient.doGet(originalUrl, null, false, null); + text = EntityUtils.toString(entity); + } catch (Exception e) { + LOG.info(e.getMessage()); + return; + } + 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> getPossibleUrlMap() { + Map> possibleUrlMap = new HashMap>(); + possibleUrlMap.put("wx2.qq.com", new ArrayList() { + /** + * + */ + private static final long serialVersionUID = 1L; + + { + add("file.wx2.qq.com"); + add("webpush.wx2.qq.com"); + } + }); + possibleUrlMap.put("wx8.qq.com", new ArrayList() { + /** + * + */ + private static final long serialVersionUID = 1L; + + { + add("file.wx8.qq.com"); + add("webpush.wx8.qq.com"); + } + }); + + possibleUrlMap.put("web2.wechat.com", new ArrayList() { + /** + * + */ + private static final long serialVersionUID = 1L; + + { + add("file.web2.wechat.com"); + add("webpush.web2.wechat.com"); + } + }); + possibleUrlMap.put("wechat.com", new ArrayList() { + /** + * + */ + 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 2017年5月12日 上午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 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 2017年4月16日 上午11:11:34 + * @return + * + */ + private Map syncCheck() { + Map resultMap = new HashMap(); + // 组装请求URL和参数 + String url = core.getLoginInfo().get(StorageLoginInfoEnum.syncUrl.getKey()) + URLEnum.SYNC_CHECK_URL.getUrl(); + List params = new ArrayList(); + 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; + } + +} diff --git a/src/main/java/cn/zhouyafeng/itchat4j/utils/Config.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/Config.java index d5a1694..c64472b 100644 --- a/src/main/java/cn/zhouyafeng/itchat4j/utils/Config.java +++ b/src/main/java/cn/zhouyafeng/itchat4j/utils/Config.java @@ -5,6 +5,8 @@ import java.util.ArrayList; import java.util.Arrays; +import cn.zhouyafeng.itchat4j.utils.enums.OsNameEnum; + /** * 配置信息 * @@ -14,6 +16,9 @@ * */ 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"; @@ -52,18 +57,18 @@ public static String getLocalPath() { * @author https://github.com/yaphone * @date 2017年4月8日 下午10:27:53 */ - public static OsName getOsName() { + public static OsNameEnum getOsNameEnum() { String os = System.getProperty("os.name").toUpperCase(); - if (os.indexOf(OsName.DARWIN.toString()) >= 0) { - return OsName.DARWIN; - } else if (os.indexOf(OsName.WINDOWS.toString()) >= 0) { - return OsName.WINDOWS; - } else if (os.indexOf(OsName.LINUX.toString()) >= 0) { - return OsName.LINUX; - } else if (os.indexOf(OsName.MAC.toString()) >= 0) { - return OsName.MAC; + 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 OsName.OTHER; + return OsNameEnum.OTHER; } } diff --git a/src/main/java/cn/zhouyafeng/itchat4j/utils/Constant.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/Constant.java deleted file mode 100644 index 9070cc4..0000000 --- a/src/main/java/cn/zhouyafeng/itchat4j/utils/Constant.java +++ /dev/null @@ -1,6 +0,0 @@ -package cn.zhouyafeng.itchat4j.utils; - -public class Constant { - public static final String API_WXAPPID = "API_WXAPPID"; - -} diff --git a/src/main/java/cn/zhouyafeng/itchat4j/utils/Contact.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/Contact.java deleted file mode 100644 index 9a7cbf8..0000000 --- a/src/main/java/cn/zhouyafeng/itchat4j/utils/Contact.java +++ /dev/null @@ -1,89 +0,0 @@ -package cn.zhouyafeng.itchat4j.utils; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.logging.Logger; - -import org.apache.http.HttpEntity; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.util.EntityUtils; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; - -public class Contact { - Logger logger = Logger.getLogger("Contact"); - Core core = Core.getInstance(); - CloseableHttpClient httpClient = MyHttpClient.getHttpClient(); - - public List getContact(boolean update) { - String url = String.format("%s/webwxgetcontact?r=%s&seq=0&skey=%s", core.loginInfo.get("url"), - String.valueOf(new Date().getTime()), core.loginInfo.get("skey")); - HttpGet httpGet = new HttpGet(url); - httpGet.setHeader("ContentType", "application/json; charset=UTF-8"); - httpGet.setHeader("User-Agent", Config.USER_AGENT); - try { - CloseableHttpResponse response = httpClient.execute(httpGet); - HttpEntity entity = response.getEntity(); - if (entity != null) { - String text = EntityUtils.toString(entity, "UTF-8"); - JSONObject obj = JSON.parseObject(text); - JSONArray tmpList = obj.getJSONArray("MemberList"); - List chatroomList = new ArrayList(); - List otherList = new ArrayList(); - for (int i = 0; i < tmpList.size(); i++) { - JSONObject m = tmpList.getJSONObject(i); - if (m.containsKey("Sex")) { - otherList.add(m); - } else { - JSONObject tmpObj = m.getJSONObject("UserName"); - if (tmpObj.toJSONString().contains("@@")) { - chatroomList.add(m); - } else if (tmpObj.toJSONString().contains("@")) { - otherList.add(m); - } - } - } - if (chatroomList.size() > 0) { - updateLocalChatrooms(chatroomList); - } - if (otherList.size() > 0) { - updateLocalFriends(otherList); - } - } - } catch (Exception e) { - logger.info(e.getMessage()); - } - return null; - - } - - Map updateLocalChatrooms(List chatrooms) { - for (JSONObject chatroom : chatrooms) { - // TODO utils.emoji_formatter(chatroom, 'NickName') - // TODO - } - - return null; - } - - void updateLocalFriends(List list) { - List fullList = new ArrayList(); - fullList.addAll(list); - fullList.addAll(core.getMemberList()); - for (int i = 0; i < fullList.size(); i++) { - JSONObject friend = fullList.get(i); - // TODO - // if 'NickName' in friend: - // utils.emoji_formatter(friend, 'NickName') - // if 'DisplayName' in friend: - // utils.emoji_formatter(friend, 'DisplayName') - core.getMemberList().add(friend); - } - } -} diff --git a/src/main/java/cn/zhouyafeng/itchat4j/utils/DownloadTools.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/DownloadTools.java deleted file mode 100644 index be1c73a..0000000 --- a/src/main/java/cn/zhouyafeng/itchat4j/utils/DownloadTools.java +++ /dev/null @@ -1,70 +0,0 @@ -package cn.zhouyafeng.itchat4j.utils; - -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 com.alibaba.fastjson.JSONObject; - -/** - * 下载处理类 - * - * @author https://github.com/yaphone - * @date 创建时间:2017年4月21日 下午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 2017年4月21日 下午11:00:25 - * @param url - * @param msgId - * @param path - * @return - */ - public static Object getDownloadFn(JSONObject msg, String type, String path) { - Map headerMap = new HashMap(); - List params = new ArrayList(); - String url = ""; - if (type.equals(MsgType.PIC)) { - url = String.format("%s/webwxgetmsgimg", (String) core.getLoginInfo().get("url")); - } else if (type.equals(MsgType.VOICE)) { - url = String.format("%s/webwxgetvoice", (String) core.getLoginInfo().get("url")); - } else if (type.equals(MsgType.VIEDO)) { - headerMap.put("Range", "bytes=0-"); - url = String.format("%s/webwxgetvideo", (String) core.getLoginInfo().get("url")); - } - params.add(new BasicNameValuePair("msgid", msg.getString("NewMsgId"))); - 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; - }; - -} diff --git a/src/main/java/cn/zhouyafeng/itchat4j/utils/MsgCodeEnum.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/MsgCodeEnum.java new file mode 100644 index 0000000..5e79710 --- /dev/null +++ b/src/main/java/cn/zhouyafeng/itchat4j/utils/MsgCodeEnum.java @@ -0,0 +1,68 @@ +package cn.zhouyafeng.itchat4j.utils; + +/** + * 消息类型 + * + * @author https://github.com/yaphone + * @date 创建时间:2017年4月23日 下午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_APP(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; + } + +} diff --git a/src/main/java/cn/zhouyafeng/itchat4j/utils/MsgType.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/MsgType.java deleted file mode 100644 index 7f0e551..0000000 --- a/src/main/java/cn/zhouyafeng/itchat4j/utils/MsgType.java +++ /dev/null @@ -1,43 +0,0 @@ -package cn.zhouyafeng.itchat4j.utils; - -/** - * 消息类型 - * - * @author https://github.com/yaphone - * @date 创建时间:2017年4月23日 下午12:15:00 - * @version 1.0 - * - */ -public class MsgType { - - 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; - - // 文本信息 - public static String TEXT = "Text"; - // 图片信息 - public static String PIC = "Pic"; - // 语音信息 - public static String VOICE = "Voice"; - // 小视频消息 - public static String VIEDO = "Video"; - // name card 明片消息 - public static String NAMECARD = "NameCard"; - -} diff --git a/src/main/java/cn/zhouyafeng/itchat4j/utils/MyHttpClient.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/MyHttpClient.java index d5e7a66..06d7b90 100644 --- a/src/main/java/cn/zhouyafeng/itchat4j/utils/MyHttpClient.java +++ b/src/main/java/cn/zhouyafeng/itchat4j/utils/MyHttpClient.java @@ -99,6 +99,7 @@ public HttpEntity doGet(String url, List params, boolean red if (params != null) { String paramStr = EntityUtils.toString(new UrlEncodedFormEntity(params, Consts.UTF_8)); httpGet = new HttpGet(url + "?" + paramStr); + } else { httpGet = new HttpGet(url); } diff --git a/src/main/java/cn/zhouyafeng/itchat4j/utils/SleepUtils.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/SleepUtils.java new file mode 100644 index 0000000..e1ebc6b --- /dev/null +++ b/src/main/java/cn/zhouyafeng/itchat4j/utils/SleepUtils.java @@ -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(); + } + } + +} diff --git a/src/main/java/cn/zhouyafeng/itchat4j/utils/Storage.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/Storage.java deleted file mode 100644 index bf8950b..0000000 --- a/src/main/java/cn/zhouyafeng/itchat4j/utils/Storage.java +++ /dev/null @@ -1,136 +0,0 @@ -package cn.zhouyafeng.itchat4j.utils; - -import java.util.ArrayList; -import java.util.List; - -import com.alibaba.fastjson.JSONObject; - -/** - * 存储登陆信息、好友列表等,全局只保存一份,单例模式 - * - * @author https://github.com/yaphone - * @date 创建时间:2017年4月23日 下午12:04:48 - * @version 1.0 - * - */ -public class Storage { - - private static Storage instance; - - private Storage() { - }; - - public static Storage getInstance() { - if (instance == null) { - synchronized (Storage.class) { - if (instance == null) { - instance = new Storage(); - } - } - } - return instance; - } - - private String userName; - private String nickName; - private List msgList = new ArrayList(); - - private List userSelfList = new ArrayList(); // 登陆账号自身信息 - private List memberList = new ArrayList(); // 好友+群聊+公众号+特殊账号 - private List contactList = new ArrayList();// 好友 - private List groupList = new ArrayList(); // 群 - private List groupMemeberList = new ArrayList(); // 群聊成员字典 - private List publicUsersList = new ArrayList();// 公众号/服务号 - private List specialUsersList = new ArrayList();// 特殊账号 - - private String lastInputUserName; - - public String getUserName() { - return userName; - } - - public void setUserName(String userName) { - this.userName = userName; - } - - public String getNickName() { - return nickName; - } - - public String getLastInputUserName() { - return lastInputUserName; - } - - public void setLastInputUserName(String lastInputUserName) { - this.lastInputUserName = lastInputUserName; - } - - public void setNickName(String nickName) { - this.nickName = nickName; - } - - public List getMemberList() { - return memberList; - } - - public void setMemberList(List memberList) { - this.memberList = memberList; - } - - public List getUserSelfList() { - return userSelfList; - } - - public void setUserSelfList(List userSelfList) { - this.userSelfList = userSelfList; - } - - public List getContactList() { - return contactList; - } - - public void setContactList(List contactList) { - this.contactList = contactList; - } - - public List getGroupList() { - return groupList; - } - - public void setGroupList(List groupList) { - this.groupList = groupList; - } - - public List getGroupMemeberList() { - return groupMemeberList; - } - - public void setGroupMemeberList(List groupMemeberList) { - this.groupMemeberList = groupMemeberList; - } - - public List getPublicUsersList() { - return publicUsersList; - } - - public void setPublicUsersList(List publicUsersList) { - this.publicUsersList = publicUsersList; - } - - public List getSpecialUsersList() { - return specialUsersList; - } - - public void setSpecialUsersList(List specialUsersList) { - this.specialUsersList = specialUsersList; - } - - public List getMsgList() { - return msgList; - } - - public void setMsgList(List msgList) { - this.msgList = msgList; - } - -} \ No newline at end of file diff --git a/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/MsgTypeEnum.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/MsgTypeEnum.java new file mode 100644 index 0000000..82caca5 --- /dev/null +++ b/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/MsgTypeEnum.java @@ -0,0 +1,34 @@ +package cn.zhouyafeng.itchat4j.utils.enums; + +/** + * 消息类型枚举类 + * + * @author https://github.com/yaphone + * @date 创建时间:2017年5月13日 下午11:53:00 + * @version 1.0 + * + */ +public enum MsgTypeEnum { + TEXT("Text", "文本消息"), + PIC("Pic", "图片消息"), + VOICE("Voice", "语音消息"), + VIEDO("Viedo", "小视频消息"), + NAMECARD("NameCard", "名片消息"); + + 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; + } + +} diff --git a/src/main/java/cn/zhouyafeng/itchat4j/utils/OsName.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/OsNameEnum.java similarity index 72% rename from src/main/java/cn/zhouyafeng/itchat4j/utils/OsName.java rename to src/main/java/cn/zhouyafeng/itchat4j/utils/enums/OsNameEnum.java index 643e86b..cfcd4ab 100644 --- a/src/main/java/cn/zhouyafeng/itchat4j/utils/OsName.java +++ b/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/OsNameEnum.java @@ -1,4 +1,4 @@ -package cn.zhouyafeng.itchat4j.utils; +package cn.zhouyafeng.itchat4j.utils.enums; /** * 系统平台 @@ -8,6 +8,6 @@ * @version 1.0 * */ -public enum OsName { +public enum OsNameEnum { WINDOWS, LINUX, DARWIN, MAC, OTHER } diff --git a/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/ResultEnum.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/ResultEnum.java new file mode 100644 index 0000000..f505b7d --- /dev/null +++ b/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/ResultEnum.java @@ -0,0 +1,35 @@ +package cn.zhouyafeng.itchat4j.utils.enums; + +/** + * 返回结构枚举类 + *

+ * 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; +// } +// } + +} diff --git a/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/RetCodeEnum.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/RetCodeEnum.java new file mode 100644 index 0000000..97f807d --- /dev/null +++ b/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/RetCodeEnum.java @@ -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; + } + +} diff --git a/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/StorageLoginInfoEnum.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/StorageLoginInfoEnum.java new file mode 100644 index 0000000..1d00ea1 --- /dev/null +++ b/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/StorageLoginInfoEnum.java @@ -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; + } + +} diff --git a/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/URLEnum.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/URLEnum.java new file mode 100644 index 0000000..1656b16 --- /dev/null +++ b/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/URLEnum.java @@ -0,0 +1,40 @@ +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", "下载语音消息") + + ; + + private String url; + private String msg; + + URLEnum(String url, String msg) { + this.url = url; + this.msg = msg; + } + + + public String getUrl() { + return url; + } +} diff --git a/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/parameters/BaseParaEnum.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/parameters/BaseParaEnum.java new file mode 100644 index 0000000..8f36e8d --- /dev/null +++ b/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/parameters/BaseParaEnum.java @@ -0,0 +1,36 @@ +package cn.zhouyafeng.itchat4j.utils.enums.parameters; + +/** + * + * 基本请求参数 + * 1. webWxInit 初始化 + * 2. wxStatusNotify 微信状态通知 + * + *

+ * 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; + } + +} diff --git a/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/parameters/LoginParaEnum.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/parameters/LoginParaEnum.java new file mode 100644 index 0000000..0c0021a --- /dev/null +++ b/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/parameters/LoginParaEnum.java @@ -0,0 +1,31 @@ +package cn.zhouyafeng.itchat4j.utils.enums.parameters; + +/** + * 登陆 + *

+ * 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; + } +} diff --git a/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/parameters/StatusNotifyParaEnum.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/parameters/StatusNotifyParaEnum.java new file mode 100644 index 0000000..9bbdf32 --- /dev/null +++ b/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/parameters/StatusNotifyParaEnum.java @@ -0,0 +1,30 @@ +package cn.zhouyafeng.itchat4j.utils.enums.parameters; + +/** + * 状态通知 + *

+ * 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; + } +} diff --git a/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/parameters/UUIDParaEnum.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/parameters/UUIDParaEnum.java new file mode 100644 index 0000000..ef716e8 --- /dev/null +++ b/src/main/java/cn/zhouyafeng/itchat4j/utils/enums/parameters/UUIDParaEnum.java @@ -0,0 +1,30 @@ +package cn.zhouyafeng.itchat4j.utils.enums.parameters; + +/** + * UUID + *

+ * 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; + } +} diff --git a/src/main/java/cn/zhouyafeng/itchat4j/tools/CommonTool.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/tools/CommonTools.java similarity index 94% rename from src/main/java/cn/zhouyafeng/itchat4j/tools/CommonTool.java rename to src/main/java/cn/zhouyafeng/itchat4j/utils/tools/CommonTools.java index 8101a3a..8e2672f 100644 --- a/src/main/java/cn/zhouyafeng/itchat4j/tools/CommonTool.java +++ b/src/main/java/cn/zhouyafeng/itchat4j/utils/tools/CommonTools.java @@ -1,4 +1,4 @@ -package cn.zhouyafeng.itchat4j.tools; +package cn.zhouyafeng.itchat4j.utils.tools; import java.io.StringReader; import java.util.ArrayList; @@ -21,7 +21,7 @@ import com.vdurmont.emoji.EmojiParser; import cn.zhouyafeng.itchat4j.utils.Config; -import cn.zhouyafeng.itchat4j.utils.OsName; +import cn.zhouyafeng.itchat4j.utils.enums.OsNameEnum; /** * 常用工具类 @@ -31,13 +31,13 @@ * @version 1.0 * */ -public class CommonTool { +public class CommonTools { public static boolean printQr(String qrPath) { - switch (Config.getOsName()) { + switch (Config.getOsNameEnum()) { case WINDOWS: - if (Config.getOsName().equals(OsName.WINDOWS)) { + if (Config.getOsNameEnum().equals(OsNameEnum.WINDOWS)) { Runtime runtime = Runtime.getRuntime(); try { runtime.exec("cmd /c start " + qrPath); @@ -47,7 +47,7 @@ public static boolean printQr(String qrPath) { } break; case MAC: - if (Config.getOsName().equals(OsName.MAC)) { + if (Config.getOsNameEnum().equals(OsNameEnum.MAC)) { Runtime runtime = Runtime.getRuntime(); try { runtime.exec("open " + qrPath); @@ -64,9 +64,9 @@ public static boolean printQr(String qrPath) { } public static boolean clearScreen() { - switch (Config.getOsName()) { + switch (Config.getOsNameEnum()) { case WINDOWS: - if (Config.getOsName().equals(OsName.WINDOWS)) { + if (Config.getOsNameEnum().equals(OsNameEnum.WINDOWS)) { Runtime runtime = Runtime.getRuntime(); try { runtime.exec("cmd /c " + "cls"); diff --git a/src/main/java/cn/zhouyafeng/itchat4j/tools/DownloadTools.java b/src/main/java/cn/zhouyafeng/itchat4j/utils/tools/DownloadTools.java similarity index 73% rename from src/main/java/cn/zhouyafeng/itchat4j/tools/DownloadTools.java rename to src/main/java/cn/zhouyafeng/itchat4j/utils/tools/DownloadTools.java index 44da9e7..2ab698d 100644 --- a/src/main/java/cn/zhouyafeng/itchat4j/tools/DownloadTools.java +++ b/src/main/java/cn/zhouyafeng/itchat4j/utils/tools/DownloadTools.java @@ -1,4 +1,4 @@ -package cn.zhouyafeng.itchat4j.tools; +package cn.zhouyafeng.itchat4j.utils.tools; import java.io.FileOutputStream; import java.io.OutputStream; @@ -14,9 +14,10 @@ import com.alibaba.fastjson.JSONObject; -import cn.zhouyafeng.itchat4j.utils.Core; -import cn.zhouyafeng.itchat4j.utils.MsgType; +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; /** * 下载工具类 @@ -45,13 +46,13 @@ public static Object getDownloadFn(JSONObject msg, String type, String path) { Map headerMap = new HashMap(); List params = new ArrayList(); String url = ""; - if (type.equals(MsgType.PIC)) { - url = String.format("%s/webwxgetmsgimg", (String) core.getLoginInfo().get("url")); - } else if (type.equals(MsgType.VOICE)) { - url = String.format("%s/webwxgetvoice", (String) core.getLoginInfo().get("url")); - } else if (type.equals(MsgType.VIEDO)) { + if (type.equals(MsgTypeEnum.PIC.getType())) { + url = String.format(URLEnum.WEB_WX_GET_MSG_IMG.getUrl(), core.getLoginInfo().get("url")); + } else if (type.equals(MsgTypeEnum.VOICE.getType())) { + url = String.format(URLEnum.WEB_WX_GET_VOICE.getUrl(), core.getLoginInfo().get("url")); + } else if (type.equals(MsgTypeEnum.VIEDO.getType())) { headerMap.put("Range", "bytes=0-"); - url = String.format("%s/webwxgetvideo", (String) core.getLoginInfo().get("url")); + url = String.format(URLEnum.WEB_WX_GET_VIEDO.getUrl(), core.getLoginInfo().get("url")); } params.add(new BasicNameValuePair("msgid", msg.getString("NewMsgId"))); params.add(new BasicNameValuePair("skey", (String) core.getLoginInfo().get("skey"))); diff --git a/src/main/resources/log4j.properties b/src/main/resources/log4j.properties new file mode 100644 index 0000000..dc30ec0 --- /dev/null +++ b/src/main/resources/log4j.properties @@ -0,0 +1,6 @@ +log4j.rootLogger=INFO, stdout + +log4j.appender.stdout = org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout = org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern = %d %-5p => %m%n + diff --git a/src/test/java/cn/zhouyafeng/itchat4j/demo/TulingRobot.java b/src/test/java/cn/zhouyafeng/itchat4j/demo/TulingRobot.java index 46a8b05..1770476 100644 --- a/src/test/java/cn/zhouyafeng/itchat4j/demo/TulingRobot.java +++ b/src/test/java/cn/zhouyafeng/itchat4j/demo/TulingRobot.java @@ -13,11 +13,11 @@ import com.alibaba.fastjson.JSONObject; import cn.zhouyafeng.itchat4j.Wechat; +import cn.zhouyafeng.itchat4j.core.Core; import cn.zhouyafeng.itchat4j.face.IMsgHandlerFace; -import cn.zhouyafeng.itchat4j.utils.Core; -import cn.zhouyafeng.itchat4j.utils.DownloadTools; -import cn.zhouyafeng.itchat4j.utils.MsgType; import cn.zhouyafeng.itchat4j.utils.MyHttpClient; +import cn.zhouyafeng.itchat4j.utils.enums.MsgTypeEnum; +import cn.zhouyafeng.itchat4j.utils.tools.DownloadTools; /** * 图灵机器人示例 @@ -29,7 +29,7 @@ */ public class TulingRobot implements IMsgHandlerFace { MyHttpClient myHttpClient = Core.getInstance().getMyHttpClient(); - String apiKey = "597b34bea4ec4c85a775c469c84b6817"; + String apiKey = "597b34bea4ec4c85a775c469c84b6817"; // 这里是我申请的图灵机器人API接口,每天只能5000次调用,建议自己去申请一个,免费的:) Logger logger = Logger.getLogger("TulingRobot"); @Override @@ -66,7 +66,7 @@ public String picMsgHandle(JSONObject msg) { public String voiceMsgHandle(JSONObject msg) { String fileName = String.valueOf(new Date().getTime()); String voicePath = "D://itchat4j/voice" + File.separator + fileName + ".mp3"; - DownloadTools.getDownloadFn(msg, MsgType.VOICE, voicePath); + DownloadTools.getDownloadFn(msg, MsgTypeEnum.VOICE.getType(), voicePath); return "收到语音"; } @@ -74,7 +74,7 @@ public String voiceMsgHandle(JSONObject msg) { public String viedoMsgHandle(JSONObject msg) { String fileName = String.valueOf(new Date().getTime()); String viedoPath = "D://itchat4j/viedo" + File.separator + fileName + ".mp4"; - DownloadTools.getDownloadFn(msg, MsgType.VIEDO, viedoPath); + DownloadTools.getDownloadFn(msg, MsgTypeEnum.VIEDO.getType(), viedoPath); return "收到视频"; } diff --git a/src/test/java/cn/zhouyafeng/itchat4j/demo/demo1/MyTest.java b/src/test/java/cn/zhouyafeng/itchat4j/demo/demo1/MyTest.java new file mode 100644 index 0000000..53835de --- /dev/null +++ b/src/test/java/cn/zhouyafeng/itchat4j/demo/demo1/MyTest.java @@ -0,0 +1,20 @@ +package cn.zhouyafeng.itchat4j.demo.demo1; + +import cn.zhouyafeng.itchat4j.Wechat; +import cn.zhouyafeng.itchat4j.face.IMsgHandlerFace; + +/** + * + * @author https://github.com/yaphone + * @date 创建时间:2017年4月28日 上午12:44:10 + * @version 1.0 + * + */ +public class MyTest { + public static void main(String[] args) { + String qrPath = "D://itchat4j//login"; // 保存登陆二维码图片的路径 + IMsgHandlerFace msgHandler = new SimpleDemo(); // 实现IMsgHandlerFace接口的类 + Wechat wechat = new Wechat(msgHandler, qrPath); // 【注入】 + wechat.start(); // 启动服务,会在qrPath下生成一张二维码图片,扫描即可登陆,注意,二维码图片如果超过一定时间未扫描会过期,过期时会自动更新,所以你可能需要重新打开图片 + } +} diff --git a/src/test/java/cn/zhouyafeng/itchat4j/demo/SimpleDemo.java b/src/test/java/cn/zhouyafeng/itchat4j/demo/demo1/SimpleDemo.java similarity index 55% rename from src/test/java/cn/zhouyafeng/itchat4j/demo/SimpleDemo.java rename to src/test/java/cn/zhouyafeng/itchat4j/demo/demo1/SimpleDemo.java index 40f9e8a..597fa89 100644 --- a/src/test/java/cn/zhouyafeng/itchat4j/demo/SimpleDemo.java +++ b/src/test/java/cn/zhouyafeng/itchat4j/demo/demo1/SimpleDemo.java @@ -1,15 +1,17 @@ -package cn.zhouyafeng.itchat4j.demo; +package cn.zhouyafeng.itchat4j.demo.demo1; import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; +import org.apache.log4j.Logger; + import com.alibaba.fastjson.JSONObject; -import cn.zhouyafeng.itchat4j.Wechat; +import cn.zhouyafeng.itchat4j.api.MessageTools; import cn.zhouyafeng.itchat4j.face.IMsgHandlerFace; -import cn.zhouyafeng.itchat4j.utils.DownloadTools; -import cn.zhouyafeng.itchat4j.utils.MsgType; +import cn.zhouyafeng.itchat4j.utils.enums.MsgTypeEnum; +import cn.zhouyafeng.itchat4j.utils.tools.DownloadTools; /** * 简单示例程序,收到文本信息自动回复原信息,收到图片、语音、小视频后根据路径自动保存 @@ -20,27 +22,25 @@ * */ public class SimpleDemo implements IMsgHandlerFace { + Logger LOG = Logger.getLogger(SimpleDemo.class); @Override public String textMsgHandle(JSONObject msg) { - // String docFilePath = "D:/itchat4j/pic/test.docx"; - // String pngFilePath = "D:/itchat4j/pic/test.png"; - // String pdfFilePath = "D:/itchat4j/pic/测试.pdf"; - // String txtFilePath = "D:/itchat4j/pic/test.txt"; - // MessageTools.sendFileMsgByNickName("yaphone", docFilePath); - // MessageTools.sendFileMsgByNickName("yaphone", pngFilePath); - // MessageTools.sendFileMsgByNickName("yaphone", pdfFilePath); - // MessageTools.sendFileMsgByNickName("yaphone", txtFilePath); - String text = msg.getString("Text"); - return text; - // return null; + String docFilePath = "D:/itchat4j/pic/test.docx"; // 这里是需要发送的文件的路径 + if (!msg.getBoolean("groupMsg")) { // 群消息不处理 + String userId = msg.getString("FromUserName"); + MessageTools.sendFileMsgByUserId(userId, docFilePath); // 发送文件 + String text = msg.getString("Text"); // 发送文本消息,也可调用MessageTools.sendFileMsgByUserId(userId,text); + return text; + } + return null; } @Override public String picMsgHandle(JSONObject 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, MsgType.PIC, picPath); + 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 "图片保存成功"; } @@ -48,7 +48,7 @@ public String picMsgHandle(JSONObject msg) { public String voiceMsgHandle(JSONObject 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, MsgType.VOICE, voicePath); + DownloadTools.getDownloadFn(msg, MsgTypeEnum.VOICE.getType(), voicePath); return "声音保存成功"; } @@ -57,7 +57,7 @@ public String viedoMsgHandle(JSONObject msg) { System.out.println(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, MsgType.VIEDO, viedoPath); + DownloadTools.getDownloadFn(msg, MsgTypeEnum.VIEDO.getType(), viedoPath); return "视频保存成功"; } @@ -66,10 +66,4 @@ public String nameCardMsgHandle(JSONObject msg) { return "收到名片消息"; } - public static void main(String[] args) { - IMsgHandlerFace msgHandler = new SimpleDemo(); - Wechat wechat = new Wechat(msgHandler, "D://itchat4j/login"); - wechat.start(); - } - }