From 266fda84337ef999847ddbfe3231d7c190173c8c Mon Sep 17 00:00:00 2001 From: hotlcc Date: Mon, 23 Jul 2018 18:22:06 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/hotlcc/wechat4j/Wechat.java | 328 +++++++++++++++++- .../com/hotlcc/wechat4j/api/WebWeixinApi.java | 31 ++ .../hotlcc/wechat4j/util/PropertiesUtil.java | 24 ++ src/main/resources/config/app.properties | 4 +- .../resources/config/webwx-url.properties | 2 + src/test/java/TestClass.java | 9 +- src/test/java/TestClass2.java | 12 + 7 files changed, 393 insertions(+), 17 deletions(-) create mode 100644 src/test/java/TestClass2.java diff --git a/src/main/java/com/hotlcc/wechat4j/Wechat.java b/src/main/java/com/hotlcc/wechat4j/Wechat.java index b78339e..2780030 100644 --- a/src/main/java/com/hotlcc/wechat4j/Wechat.java +++ b/src/main/java/com/hotlcc/wechat4j/Wechat.java @@ -3,7 +3,9 @@ package com.hotlcc.wechat4j; import com.alibaba.fastjson.JSONObject; import com.hotlcc.wechat4j.api.WebWeixinApi; import com.hotlcc.wechat4j.enums.LoginTipEnum; +import com.hotlcc.wechat4j.util.PropertiesUtil; import com.hotlcc.wechat4j.util.QRCodeUtil; +import com.hotlcc.wechat4j.util.StringUtil; import org.apache.http.client.CookieStore; import org.apache.http.client.HttpClient; import org.apache.http.impl.client.BasicCookieStore; @@ -11,6 +13,9 @@ import org.apache.http.impl.client.HttpClients; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.OutputStream; +import java.io.PrintStream; + /** * 微信客户端 * @@ -19,14 +24,18 @@ import org.slf4j.LoggerFactory; public class Wechat { private static Logger logger = LoggerFactory.getLogger(Wechat.class); + private WebWeixinApi webWeixinApi; + private CookieStore cookieStore; private HttpClient httpClient; - private WebWeixinApi webWeixinApi; + //在线状态 + private volatile boolean isOnline = false; - public void setWebWeixinApi(WebWeixinApi webWeixinApi) { - this.webWeixinApi = webWeixinApi; - } + private volatile String wxsid; + private volatile String passTicket; + private volatile String skey; + private volatile String wxuin; public Wechat(CookieStore cookieStore) { this.cookieStore = cookieStore; @@ -38,11 +47,290 @@ public class Wechat { this.httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build(); } + public void setWebWeixinApi(WebWeixinApi webWeixinApi) { + this.webWeixinApi = webWeixinApi; + } + + /** + * 获取uuid + * + * @param ps + * @param time + * @return + */ + private String getWxUuid(PrintStream ps, int time) { + ps.print("尝试正常方式获取uuid..."); + ps.flush(); + + for (int i = 0; i <= time; i++) { + if (i > 0) { + ps.print("\t第" + i + "次尝试..."); + ps.flush(); + } + JSONObject result = webWeixinApi.getWxUuid(httpClient); + + if (result == null) { + ps.println("\t失败:出现异常"); + ps.flush(); + return null; + } + + String code = result.getString("code"); + String uuid = result.getString("uuid"); + if (!"200".equals(code)) { + String msg = result.getString("msg"); + ps.println("\t失败:" + msg); + ps.flush(); + return null; + } + + if (StringUtil.isEmpty(uuid)) { + ps.print("\t失败"); + if (i == 0 && time > 0) { + ps.print(",将重复尝试" + time + "次"); + } + ps.println(); + ps.flush(); + continue; + } + + ps.println("\t成功,值为:" + uuid); + ps.flush(); + return uuid; + } + return null; + } + + /** + * 获取并显示qrcode + * + * @return + */ + private boolean getAndShowQRCode(PrintStream ps, String uuid, int time) { + ps.print("获取二维码..."); + ps.flush(); + + for (int i = 0; i <= time; i++) { + if (i > 0) { + ps.print("\t第" + i + "次尝试..."); + ps.flush(); + } + + byte[] data = webWeixinApi.getQR(httpClient, uuid); + + if (data == null || data.length <= 0) { + ps.print("\t失败"); + if (i == 0 && time > 0) { + ps.print(",将重新获取uuid并重复尝试" + time + "次"); + } + ps.println(); + ps.flush(); + getWxUuid(ps, 0); + continue; + } + + ps.println("\t成功,请扫描二维码:"); + ps.flush(); + ps.println(QRCodeUtil.toCharMatrix(data)); + ps.flush(); + QRCodeUtil.openQRCodeImage(data); + return true; + } + + return false; + } + + /** + * 等待手机端确认登录 + * + * @return + */ + private String waitForConfirm(PrintStream ps, String uuid) { + ps.print("等待手机端扫码..."); + ps.flush(); + + String code = null; + boolean flag = false; + while (!"200".equals(code)) { + JSONObject result = webWeixinApi.getRedirectUri(httpClient, LoginTipEnum.TIP_0, uuid); + if (result == null) { + ps.println("\t失败:出现异常"); + ps.flush(); + return null; + } + + code = result.getString("code"); + if ("408".equals(code)) { + ps.print("."); + ps.flush(); + continue; + } else if ("400".equals(code)) { + ps.println("\t失败,二维码失效"); + ps.flush(); + return null; + } else if ("201".equals(code)) { + if (!flag) { + ps.println(); + ps.print("请确认登录..."); + ps.flush(); + flag = true; + } + continue; + } else if ("200".equals(code)) { + String redirectUri = result.getString("redirectUri"); + ps.println("\t成功,认证完成"); + ps.flush(); + return redirectUri; + } else { + return null; + } + } + return null; + } + + /** + * 获取登录认证码 + */ + private boolean getLoginCode(PrintStream ps, String redirectUri) { + ps.print("获取登录认证码..."); + ps.flush(); + + JSONObject result = webWeixinApi.getLoginCode(httpClient, redirectUri); + if (result == null) { + ps.println("\t失败:出现异常"); + ps.flush(); + return false; + } + + String ret = result.getString("ret"); + if (!"0".equals(ret)) { + ps.println("\t失败:错误的返回码(" + ret + ")"); + ps.flush(); + return false; + } + + wxsid = result.getString("wxsid"); + passTicket = result.getString("pass_ticket"); + skey = result.getString("skey"); + wxuin = result.getString("wxuin"); + isOnline = true; + + ps.println("\t成功"); + ps.flush(); + + return true; + } + + /** + * push方式获取uuid + * + * @param ps + * @param wxuin + * @return + */ + private String getWxUuid(PrintStream ps, String wxuin) { + ps.print("尝试push方式获取uuid..."); + ps.flush(); + + JSONObject result = webWeixinApi.pushLogin(httpClient, wxuin); + if (result == null) { + ps.println("\t失败:出现异常"); + ps.flush(); + return null; + } + + String ret = result.getString("ret"); + if (!"0".equals(ret)) { + ps.println("\t失败:错误的返回码(" + ret + ")"); + ps.flush(); + return null; + } + + String uuid = result.getString("uuid"); + if (StringUtil.isEmpty(uuid)) { + ps.println("\t失败:空值"); + ps.flush(); + return null; + } + + ps.println("\t成功,值为:" + uuid); + ps.flush(); + + return uuid; + } + /** * 自动登录 */ - public void autoLogin() { + public boolean autoLogin(OutputStream os) { + // 0、获取消息打印流 + PrintStream ps = null; + if (os != null) { + ps = new PrintStream(os); + } else { + ps = System.out; + } + // 1、判断是否已经登录 + if (isOnline) { + ps.println("当前已是登录状态,无需登录"); + return true; + } + + JSONObject result = null; + int time = PropertiesUtil.getIntValue("wechat4j.retry.time", 3); + + // 2、登录 + // 2.1、获取uuid + String uuid = null; + if (StringUtil.isNotEmpty(wxuin)) { + uuid = getWxUuid(ps, wxuin); + } + if (StringUtil.isEmpty(uuid)) { + uuid = getWxUuid(ps, time); + } + if (StringUtil.isEmpty(uuid)) { + ps.println("无法获取uuid,登录不成功"); + ps.flush(); + return false; + } + // 2.2、获取并显示二维码 + if (!getAndShowQRCode(ps, uuid, time)) { + ps.println("无法获取二维码,登录不成功"); + ps.flush(); + return false; + } + // 2.3、等待确认 + String redirectUri = waitForConfirm(ps, uuid); + if (StringUtil.isEmpty(redirectUri)) { + ps.println("手机端认证失败,登录不成功"); + ps.flush(); + return false; + } + // 2.4、获取登录认证码 + if (!getLoginCode(ps, redirectUri)) { + ps.println("无法获取登录认证码,登录不成功"); + ps.flush(); + return false; + } + + return true; + } + + /** + * 自动登录 + * + * @return + */ + public boolean autoLogin() { + return autoLogin(null); + } + + /** + * 退出登录 + */ + public void logout() { + webWeixinApi.logout(httpClient, wxsid, skey, wxuin); } public void test() { @@ -116,9 +404,9 @@ public class Wechat { JSONObject SyncKey = result.getJSONObject("SyncKey"); logger.info("初始化数据完成"); //6、开启消息状态通知 - logger.info("开始开启消息状态通知"); - result = webWeixinApi.statusNotify(httpClient, passTicket, wxsid, skey, wxuin, loginUser.getString("UserName")); - logger.info("开启消息状态通知完成"); +// logger.info("开始开启消息状态通知"); +// result = webWeixinApi.statusNotify(httpClient, passTicket, wxsid, skey, wxuin, loginUser.getString("UserName")); +// logger.info("开启消息状态通知完成"); //7、获取联系人信息 // logger.info("开始获取全部联系人"); // result = webWeixinApi.getContact(httpClient, passTicket, wxsid); @@ -127,7 +415,17 @@ public class Wechat { // System.out.println("昵称\t备注名\tUserName"); // for (int i = 0, len = MemberList.size(); i < len; i++) { // JSONObject Member = MemberList.getJSONObject(i); -// System.out.println(Member.getString("NickName") + "\t" + Member.getString("RemarkName") + "\t" + Member.getString("UserName")); +// if ("BYCX-IT".equals(Member.getString("NickName"))) { +// System.out.println(Member); +// JSONArray params = new JSONArray(); +// JSONObject param = new JSONObject(); +// param.put("EncryChatRoomId", ""); +// param.put("UserName", Member.getString("UserName")); +// params.add(param); +// result = webWeixinApi.batchGetContact(httpClient, passTicket, wxsid, skey, wxuin, params); +// System.out.println(result); +// break; +// } // } // logger.info("获取全部联系人完成,共{}条", MemberList.size()); //7、服务端状态同步 @@ -163,11 +461,11 @@ public class Wechat { // } // } //测试给特定联系人发送文本信息 - result = webWeixinApi.sendMsg(httpClient, passTicket, wxsid, skey, wxuin, - "测试消息", - 1, - loginUser.getString("UserName"), - "@493f6dbadb4ed2f471b8098fd7f6db1bbcc7294e829e8ecbdc6d2b32647bc2d2"); - System.out.println(result); +// result = webWeixinApi.sendMsg(httpClient, passTicket, wxsid, skey, wxuin, +// "测试消息", +// 1, +// loginUser.getString("UserName"), +// "@493f6dbadb4ed2f471b8098fd7f6db1bbcc7294e829e8ecbdc6d2b32647bc2d2"); +// System.out.println(result); } } diff --git a/src/main/java/com/hotlcc/wechat4j/api/WebWeixinApi.java b/src/main/java/com/hotlcc/wechat4j/api/WebWeixinApi.java index b1753a1..4b5acf1 100644 --- a/src/main/java/com/hotlcc/wechat4j/api/WebWeixinApi.java +++ b/src/main/java/com/hotlcc/wechat4j/api/WebWeixinApi.java @@ -258,6 +258,37 @@ public class WebWeixinApi { } } + /** + * push登录 + */ + public JSONObject pushLogin(HttpClient httpClient, + String wxuin) { + try { + long millis = System.currentTimeMillis(); + String url = new ST(PropertiesUtil.getProperty("webwx-url.pushlogin_url")) + .add("uin", wxuin) + .render(); + + HttpGet httpGet = new HttpGet(url); + httpGet.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent")); + httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build()); + + HttpResponse response = httpClient.execute(httpGet); + int statusCode = response.getStatusLine().getStatusCode(); + if (HttpStatus.SC_OK != statusCode) { + throw new RuntimeException("响应失败(" + statusCode + ")"); + } + + HttpEntity entity = response.getEntity(); + String res = EntityUtils.toString(entity, Consts.UTF_8); + + return JSONObject.parseObject(res); + } catch (Exception e) { + logger.error("push登录异常", e); + return null; + } + } + /** * 获取初始化数据 */ diff --git a/src/main/java/com/hotlcc/wechat4j/util/PropertiesUtil.java b/src/main/java/com/hotlcc/wechat4j/util/PropertiesUtil.java index 75a50a7..c1aaa4c 100644 --- a/src/main/java/com/hotlcc/wechat4j/util/PropertiesUtil.java +++ b/src/main/java/com/hotlcc/wechat4j/util/PropertiesUtil.java @@ -53,4 +53,28 @@ public final class PropertiesUtil { public static String getProperty(String key, String defaultValue) { return prop.getProperty(key, defaultValue); } + + public static Integer getInteger(String key, Integer defaultValue) { + String p = getProperty(key); + if (p == null) { + return defaultValue; + } + p.trim(); + if ("".equals(p)) { + return defaultValue; + } + return Integer.valueOf(p); + } + + public static Integer getInteger(String key) { + return getInteger(key, null); + } + + public static int getIntValue(String key, int defaultValue) { + return getInteger(key, defaultValue); + } + + public static int getIntValue(String key) { + return getInteger(key); + } } diff --git a/src/main/resources/config/app.properties b/src/main/resources/config/app.properties index d4556d1..5f24d09 100644 --- a/src/main/resources/config/app.properties +++ b/src/main/resources/config/app.properties @@ -3,4 +3,6 @@ webwx.appid=wx782c26e4c19acffb # httpclient的UserAgent wechat4j.userAgent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36 # QRCode图片临时文件前缀 -wechat4j.qrcode.tmpfile.prefix=wechat4j_tmp_ \ No newline at end of file +wechat4j.qrcode.tmpfile.prefix=wechat4j_tmp_ +# 全局重试次数 +wechat4j.retry.time=3 \ No newline at end of file diff --git a/src/main/resources/config/webwx-url.properties b/src/main/resources/config/webwx-url.properties index c46816b..416fcaa 100644 --- a/src/main/resources/config/webwx-url.properties +++ b/src/main/resources/config/webwx-url.properties @@ -9,6 +9,8 @@ webwx-url.redirect_uri=https://login.wx2.qq.com/cgi-bin/mmwebwx-bin/login?logini webwx-url.newlogin_url=&fun=new&version=v2 ## 1.5、退出登录 webwx-url.logout_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxlogout?redirect=1&type=&skey= +## 1.6、push登录 +webwx-url.pushlogin_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxpushloginurl?uin= # 2、数据同步 ## 2.1、页面初始化 webwx-url.webwxinit_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=&lang=zh_CN&pass_ticket= diff --git a/src/test/java/TestClass.java b/src/test/java/TestClass.java index f443ed2..783719e 100644 --- a/src/test/java/TestClass.java +++ b/src/test/java/TestClass.java @@ -18,11 +18,18 @@ public class TestClass { System.out.println(QRCodeUtil.toCharMatrix(image)); } - @Test public void test04() { WebWeixinApi api = new WebWeixinApi(); Wechat wechat = new Wechat(); wechat.setWebWeixinApi(api); wechat.test(); } + + @Test + public void test05() { + WebWeixinApi api = new WebWeixinApi(); + Wechat wechat = new Wechat(); + wechat.setWebWeixinApi(api); + System.out.println(wechat.autoLogin()); + } } diff --git a/src/test/java/TestClass2.java b/src/test/java/TestClass2.java new file mode 100644 index 0000000..468dc4e --- /dev/null +++ b/src/test/java/TestClass2.java @@ -0,0 +1,12 @@ +import com.hotlcc.wechat4j.Wechat; +import com.hotlcc.wechat4j.api.WebWeixinApi; + +public class TestClass2 { + public static void main(String[] args) { + WebWeixinApi api = new WebWeixinApi(); + Wechat wechat = new Wechat(); + wechat.setWebWeixinApi(api); + System.out.println(wechat.autoLogin()); + wechat.logout(); + } +}