2
0
mirror of https://gitee.com/hotlcc/wechat4j.git synced 2025-06-10 04:24:09 +08:00

提交代码

This commit is contained in:
hotlcc 2018-07-23 12:45:05 +08:00
parent 5106ffb0bf
commit cf4d8a7973
7 changed files with 425 additions and 296 deletions

View File

@ -1,8 +1,8 @@
package com.hotlcc.wechat4j; package com.hotlcc.wechat4j;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.hotlcc.wechat4j.api.WebWeixinApi; import com.hotlcc.wechat4j.api.WebWeixinApi;
import com.hotlcc.wechat4j.enums.LoginTipEnum;
import com.hotlcc.wechat4j.util.QRCodeUtil; import com.hotlcc.wechat4j.util.QRCodeUtil;
import org.apache.http.client.CookieStore; import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient; import org.apache.http.client.HttpClient;
@ -74,13 +74,14 @@ public class Wechat {
//2获取二维码 //2获取二维码
logger.info("开始获取二维码..."); logger.info("开始获取二维码...");
result = webWeixinApi.getQR(httpClient, uuid); byte[] data = webWeixinApi.getQR(httpClient, uuid);
logger.info("获取二维码成功,请扫描二维码:\n{}", QRCodeUtil.toCharMatrix(result.getBytes("data"))); logger.info("获取二维码成功,请扫描二维码:\n{}", QRCodeUtil.toCharMatrix(data));
QRCodeUtil.openQRCodeImage(data);
//3轮询 //3轮询
String code = null; String code = null;
while (!"200".equals(code)) { while (!"200".equals(code)) {
result = webWeixinApi.getRedirectUri(httpClient, uuid); result = webWeixinApi.getRedirectUri(httpClient, LoginTipEnum.TIP_0, uuid);
code = result.getString("code"); code = result.getString("code");
if ("408".equals(code)) { if ("408".equals(code)) {
continue; continue;
@ -118,37 +119,55 @@ public class Wechat {
logger.info("开始开启消息状态通知"); logger.info("开始开启消息状态通知");
result = webWeixinApi.statusNotify(httpClient, passTicket, wxsid, skey, wxuin, loginUser.getString("UserName")); result = webWeixinApi.statusNotify(httpClient, passTicket, wxsid, skey, wxuin, loginUser.getString("UserName"));
logger.info("开启消息状态通知完成"); logger.info("开启消息状态通知完成");
//7获取联系人信息
// logger.info("开始获取全部联系人");
// result = webWeixinApi.getContact(httpClient, passTicket, wxsid);
// JSONArray MemberList = result.getJSONArray("MemberList");
// logger.info("获取全部联系人完成,共{}条:", MemberList.size());
// 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"));
// }
// logger.info("获取全部联系人完成,共{}条", MemberList.size());
//7服务端状态同步 //7服务端状态同步
logger.info("开始轮询服务端状态"); // logger.info("开始轮询服务端状态");
while (true) { // while (true) {
result = webWeixinApi.syncCheck(httpClient, wxsid, skey, wxuin, SyncKey.getJSONArray("List")); // result = webWeixinApi.syncCheck(httpClient, wxsid, skey, wxuin, SyncKey.getJSONArray("List"));
// System.out.println(result);
// int retcode = result.getIntValue("retcode");
// if (retcode != 0) {
// logger.info("微信已退出登录retcode={}", retcode);
// break;
// } else {
// int selector = result.getIntValue("selector");
// if (selector == 2) {
// logger.info("收到新消息");
// //8获取新消息内容
// result = webWeixinApi.pullNewMsg(httpClient, passTicket, wxsid, skey, wxuin, SyncKey);
// SyncKey = result.getJSONObject("SyncKey");
// JSONArray AddMsgList = result.getJSONArray("AddMsgList");
// if (AddMsgList != null) {
// for (int i = 0, len = AddMsgList.size(); i < len; i++) {
// JSONObject Msg = AddMsgList.getJSONObject(i);
// String Content = Msg.getString("Content");
// int MsgType = Msg.getIntValue("MsgType");
// String FromUserName = Msg.getString("FromUserName");
// String ToUserName = Msg.getString("ToUserName");
// logger.info("消息类型:{},消息内容:{},发送方:{},接收方:{}", MsgType, Content, FromUserName, ToUserName);
//// result = webWeixinApi.sendMsg(httpClient, passTicket, wxsid, skey, wxuin, Content, MsgType, ToUserName, FromUserName);
//// logger.info("自动回复消息完成,返回:{}", result);
// }
// }
// }
// }
// }
//测试给特定联系人发送文本信息
result = webWeixinApi.sendMsg(httpClient, passTicket, wxsid, skey, wxuin,
"测试消息",
1,
loginUser.getString("UserName"),
"@493f6dbadb4ed2f471b8098fd7f6db1bbcc7294e829e8ecbdc6d2b32647bc2d2");
System.out.println(result); System.out.println(result);
int retcode = result.getIntValue("retcode");
if (retcode != 0) {
logger.info("微信已退出登录");
break;
} else {
int selector = result.getIntValue("selector");
if (selector == 2) {
logger.info("收到新消息");
//8获取新消息内容
result = webWeixinApi.pullNewMsg(httpClient, passTicket, wxsid, skey, wxuin, SyncKey);
SyncKey = result.getJSONObject("SyncKey");
JSONArray AddMsgList = result.getJSONArray("AddMsgList");
if (AddMsgList != null) {
for (int i = 0, len = AddMsgList.size(); i < len; i++) {
JSONObject Msg = AddMsgList.getJSONObject(i);
String Content = Msg.getString("Content");
int MsgType = Msg.getIntValue("MsgType");
String FromUserName = Msg.getString("FromUserName");
String ToUserName = Msg.getString("ToUserName");
logger.info("消息类型:{},消息内容:{},发送方:{},接收方:{}", MsgType, Content, FromUserName, ToUserName);
result = webWeixinApi.sendMsg(httpClient, passTicket, wxsid, skey, wxuin, Content, MsgType, ToUserName, FromUserName);
logger.info("自动回复消息完成,返回:{}", result);
}
}
}
}
}
} }
} }

View File

@ -2,6 +2,7 @@ package com.hotlcc.wechat4j.api;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.hotlcc.wechat4j.enums.LoginTipEnum;
import com.hotlcc.wechat4j.util.PropertiesUtil; import com.hotlcc.wechat4j.util.PropertiesUtil;
import com.hotlcc.wechat4j.util.StringUtil; import com.hotlcc.wechat4j.util.StringUtil;
import com.hotlcc.wechat4j.util.WechatUtil; import com.hotlcc.wechat4j.util.WechatUtil;
@ -20,7 +21,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.stringtemplate.v4.ST; import org.stringtemplate.v4.ST;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@ -35,6 +35,7 @@ import java.util.regex.Pattern;
public class WebWeixinApi { public class WebWeixinApi {
private static Logger logger = LoggerFactory.getLogger(WebWeixinApi.class); private static Logger logger = LoggerFactory.getLogger(WebWeixinApi.class);
//预编译正则匹配
private static Pattern PATTERN_UUID_1 = Pattern.compile("window.QRLogin.code = (\\d+);"); private static Pattern PATTERN_UUID_1 = Pattern.compile("window.QRLogin.code = (\\d+);");
private static Pattern PATTERN_UUID_2 = Pattern.compile("window.QRLogin.code = (\\d+); window.QRLogin.uuid = \"(\\S+?)\";"); private static Pattern PATTERN_UUID_2 = Pattern.compile("window.QRLogin.code = (\\d+); window.QRLogin.uuid = \"(\\S+?)\";");
private static Pattern PATTERN_REDIRECT_URI_1 = Pattern.compile("window.code=(\\d+);"); private static Pattern PATTERN_REDIRECT_URI_1 = Pattern.compile("window.code=(\\d+);");
@ -44,6 +45,7 @@ public class WebWeixinApi {
* 获取微信uuid * 获取微信uuid
*/ */
public JSONObject getWxUuid(HttpClient httpClient) { public JSONObject getWxUuid(HttpClient httpClient) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.uuid_url")) String url = new ST(PropertiesUtil.getProperty("webwx-url.uuid_url"))
.add("appid", PropertiesUtil.getProperty("webwx.appid")) .add("appid", PropertiesUtil.getProperty("webwx.appid"))
.add("_", System.currentTimeMillis()) .add("_", System.currentTimeMillis())
@ -53,47 +55,43 @@ public class WebWeixinApi {
httpGet.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent")); httpGet.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent"));
httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build()); httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build());
JSONObject result = new JSONObject();
try {
HttpResponse response = httpClient.execute(httpGet); HttpResponse response = httpClient.execute(httpGet);
if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) { int statusCode = response.getStatusLine().getStatusCode();
throw new RuntimeException("请求错误"); if (HttpStatus.SC_OK != statusCode) {
throw new RuntimeException("响应失败(" + statusCode + ")");
} }
HttpEntity entity = response.getEntity(); HttpEntity entity = response.getEntity();
String res = EntityUtils.toString(entity); String res = EntityUtils.toString(entity, Consts.UTF_8);
Matcher matcher = PATTERN_UUID_1.matcher(res); Matcher matcher = PATTERN_UUID_1.matcher(res);
if (!matcher.find()) { if (!matcher.find()) {
throw new RuntimeException("获取登录uuid失败"); throw new RuntimeException("返回数据错误");
} }
String code = matcher.group(1); String code = matcher.group(1);
JSONObject result = new JSONObject();
result.put("code", code); result.put("code", code);
if (!"200".equals(code)) { if (!"200".equals(code)) {
result.put("code", code); result.put("msg", "返回code错误请确认appid是否有效");
result.put("msg", "获取登录uuid失败请确认appid是否有效");
return result; return result;
} }
matcher = PATTERN_UUID_2.matcher(res); matcher = PATTERN_UUID_2.matcher(res);
if (!matcher.find()) { if (!matcher.find()) {
throw new RuntimeException("获取登录uuid失败"); throw new RuntimeException("没有匹配到uuid");
} }
String uuid = matcher.group(2); String uuid = matcher.group(2);
result.put("uuid", uuid); result.put("uuid", uuid);
if (StringUtil.isEmpty(uuid)) { if (StringUtil.isEmpty(uuid)) {
throw new RuntimeException("获取登录uuid失败"); throw new RuntimeException("获取的uuid为空");
} }
return result; return result;
} catch (IOException e) { } catch (Exception e) {
logger.error("获取登录uuid异常", e); logger.error("获取uuid异常", e);
result.put("code", "-1"); return null;
result.put("msg", "获取登录uuid异常");
return result;
} }
} }
@ -102,8 +100,9 @@ public class WebWeixinApi {
* *
* @param uuid * @param uuid
*/ */
public JSONObject getQR(HttpClient httpClient, public byte[] getQR(HttpClient httpClient,
String uuid) { String uuid) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.qrcode_url")) String url = new ST(PropertiesUtil.getProperty("webwx-url.qrcode_url"))
.add("uuid", uuid) .add("uuid", uuid)
.render(); .render();
@ -112,28 +111,22 @@ public class WebWeixinApi {
httpGet.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent")); httpGet.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent"));
httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build()); httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build());
JSONObject result = new JSONObject();
try {
HttpResponse response = httpClient.execute(httpGet); HttpResponse response = httpClient.execute(httpGet);
if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) { int statusCode = response.getStatusLine().getStatusCode();
throw new RuntimeException("请求错误"); if (HttpStatus.SC_OK != statusCode) {
throw new RuntimeException("响应失败(" + statusCode + ")");
} }
HttpEntity entity = response.getEntity(); HttpEntity entity = response.getEntity();
byte[] data = EntityUtils.toByteArray(entity); byte[] data = EntityUtils.toByteArray(entity);
if (data == null || data.length <= 0) { if (data == null || data.length <= 0) {
throw new RuntimeException("获取二维码失败"); throw new RuntimeException("二维码数据为空");
} }
result.put("code", "200"); return data;
result.put("data", data); } catch (Exception e) {
return result;
} catch (IOException e) {
logger.error("获取二维码异常", e); logger.error("获取二维码异常", e);
result.put("code", "-1"); return null;
result.put("msg", "获取二维码异常");
return result;
} }
} }
@ -143,9 +136,12 @@ public class WebWeixinApi {
* @return * @return
*/ */
public JSONObject getRedirectUri(HttpClient httpClient, public JSONObject getRedirectUri(HttpClient httpClient,
LoginTipEnum tip,
String uuid) { String uuid) {
try {
long millis = System.currentTimeMillis(); long millis = System.currentTimeMillis();
String url = new ST(PropertiesUtil.getProperty("webwx-url.redirect_uri")) String url = new ST(PropertiesUtil.getProperty("webwx-url.redirect_uri"))
.add("tip", tip.getCode())
.add("uuid", uuid) .add("uuid", uuid)
.add("r", millis / 1252L) .add("r", millis / 1252L)
.add("_", millis) .add("_", millis)
@ -155,23 +151,22 @@ public class WebWeixinApi {
httpGet.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent")); httpGet.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent"));
httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build()); httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build());
JSONObject result = new JSONObject();
try {
HttpResponse response = httpClient.execute(httpGet); HttpResponse response = httpClient.execute(httpGet);
if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) { int statusCode = response.getStatusLine().getStatusCode();
throw new RuntimeException("请求错误"); if (HttpStatus.SC_OK != statusCode) {
throw new RuntimeException("响应失败(" + statusCode + ")");
} }
HttpEntity entity = response.getEntity(); HttpEntity entity = response.getEntity();
String res = EntityUtils.toString(entity); String res = EntityUtils.toString(entity, Consts.UTF_8);
Matcher matcher = PATTERN_REDIRECT_URI_1.matcher(res); Matcher matcher = PATTERN_REDIRECT_URI_1.matcher(res);
if (!matcher.find()) { if (!matcher.find()) {
throw new RuntimeException("获取跳转uri失败"); throw new RuntimeException("返回数据错误");
} }
String code = matcher.group(1); String code = matcher.group(1);
JSONObject result = new JSONObject();
result.put("code", code); result.put("code", code);
if ("408".equals(code)) { if ("408".equals(code)) {
result.put("msg", "请扫描二维码"); result.put("msg", "请扫描二维码");
@ -182,20 +177,18 @@ public class WebWeixinApi {
} else if ("200".equals(code)) { } else if ("200".equals(code)) {
matcher = PATTERN_REDIRECT_URI_2.matcher(res); matcher = PATTERN_REDIRECT_URI_2.matcher(res);
if (!matcher.find()) { if (!matcher.find()) {
throw new RuntimeException("获取跳转uri失败"); throw new RuntimeException("没有匹配到跳转uri");
} }
result.put("msg", "手机确认成功"); result.put("msg", "手机确认成功");
result.put("redirectUri", matcher.group(2)); result.put("redirectUri", matcher.group(2));
} else { } else {
result.put("msg", "扫码失败"); throw new RuntimeException("返回code错误");
} }
return result; return result;
} catch (IOException e) { } catch (Exception e) {
logger.error("获取跳转uri异常", e); logger.error("获取跳转uri异常", e);
result.put("code", "-3"); return null;
result.put("msg", "获取跳转uri异常");
return result;
} }
} }
@ -205,6 +198,7 @@ public class WebWeixinApi {
*/ */
public JSONObject getLoginCode(HttpClient httpClient, public JSONObject getLoginCode(HttpClient httpClient,
String redirectUri) { String redirectUri) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.newlogin_url")) String url = new ST(PropertiesUtil.getProperty("webwx-url.newlogin_url"))
.add("redirectUri", redirectUri) .add("redirectUri", redirectUri)
.render(); .render();
@ -213,30 +207,21 @@ public class WebWeixinApi {
httpGet.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent")); httpGet.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent"));
httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build()); httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build());
JSONObject result = new JSONObject();
try {
HttpResponse response = httpClient.execute(httpGet); HttpResponse response = httpClient.execute(httpGet);
if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) { int statusCode = response.getStatusLine().getStatusCode();
throw new RuntimeException("请求错误"); if (HttpStatus.SC_OK != statusCode) {
throw new RuntimeException("响应失败(" + statusCode + ")");
} }
HttpEntity entity = response.getEntity(); HttpEntity entity = response.getEntity();
String res = EntityUtils.toString(entity); String res = EntityUtils.toString(entity, Consts.UTF_8);
JSONObject json = JSONObject.parseObject(XML.toJSONObject(res).toString()).getJSONObject("error"); JSONObject result = JSONObject.parseObject(XML.toJSONObject(res).toString()).getJSONObject("error");
result.putAll(json);
result.put("msg", result.getString("message"));
if (result.getIntValue("ret") == 0) {
result.put("code", "200");
}
return result; return result;
} catch (IOException e) { } catch (Exception e) {
logger.error("获取登录认证码异常", e); logger.error("获取登录认证码异常", e);
result.put("code", "-1"); return null;
result.put("msg", "获取登录认证码异常");
return result;
} }
} }
@ -247,57 +232,41 @@ public class WebWeixinApi {
String wxsid, String wxsid,
String skey, String skey,
String wxuin) { String wxuin) {
//type=0 try {
List<NameValuePair> pairList = new ArrayList<>();
pairList.add(new BasicNameValuePair("sid", wxsid));
pairList.add(new BasicNameValuePair("uin", wxuin));
//分两步进行
for (int i = 0; i <= 1; i++) {
String url = new ST(PropertiesUtil.getProperty("webwx-url.logout_url")) String url = new ST(PropertiesUtil.getProperty("webwx-url.logout_url"))
.add("type", 0) .add("type", i)
.add("skey", StringUtil.encodeURL(skey, "UTF-8")) .add("skey", StringUtil.encodeURL(skey, Consts.UTF_8.name()))
.render(); .render();
HttpPost httpPost = new HttpPost(url); HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent")); httpPost.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent"));
httpPost.setHeader("Content-type", ContentType.APPLICATION_FORM_URLENCODED.toString()); httpPost.setHeader("Content-type", ContentType.APPLICATION_FORM_URLENCODED.toString());
List<NameValuePair> pairList = new ArrayList<>();
pairList.add(new BasicNameValuePair("sid", wxsid));
pairList.add(new BasicNameValuePair("uin", wxuin));
try {
HttpEntity paramEntity = new UrlEncodedFormEntity(pairList); HttpEntity paramEntity = new UrlEncodedFormEntity(pairList);
httpPost.setEntity(paramEntity); httpPost.setEntity(paramEntity);
httpClient.execute(httpPost); httpClient.execute(httpPost);
} catch (IOException e) {
logger.error("退出登录异常", e);
} }
} catch (Exception e) {
//type=1
String url1 = new ST(PropertiesUtil.getProperty("webwx-url.logout_url"))
.add("type", 1)
.add("skey", StringUtil.encodeURL(skey, "UTF-8"))
.render();
HttpPost httpPost1 = new HttpPost(url1);
httpPost.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent"));
httpPost.setHeader("Content-type", ContentType.APPLICATION_FORM_URLENCODED.toString());
try {
HttpEntity paramEntity = new UrlEncodedFormEntity(pairList);
httpPost.setEntity(paramEntity);
httpClient.execute(httpPost1);
} catch (IOException e) {
logger.error("退出登录异常", e); logger.error("退出登录异常", e);
} }
} }
/** /**
* 数据初始化 * 获取初始化数据
*/ */
public JSONObject webWeixinInit(HttpClient httpClient, public JSONObject webWeixinInit(HttpClient httpClient,
String passticket, String passticket,
String wxsid, String wxsid,
String skey, String skey,
String wxuin) { String wxuin) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.webwxinit_url")) String url = new ST(PropertiesUtil.getProperty("webwx-url.webwxinit_url"))
.add("pass_ticket", passticket) .add("pass_ticket", passticket)
.add("r", System.currentTimeMillis() / 1252L) .add("r", System.currentTimeMillis() / 1252L)
@ -312,18 +281,18 @@ public class WebWeixinApi {
HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8); HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8);
httpPost.setEntity(paramEntity); httpPost.setEntity(paramEntity);
try {
HttpResponse response = httpClient.execute(httpPost); HttpResponse response = httpClient.execute(httpPost);
if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) { int statusCode = response.getStatusLine().getStatusCode();
throw new RuntimeException("请求错误"); if (HttpStatus.SC_OK != statusCode) {
throw new RuntimeException("响应失败(" + statusCode + ")");
} }
HttpEntity entity = response.getEntity(); HttpEntity entity = response.getEntity();
String res = EntityUtils.toString(entity, Consts.UTF_8); String res = EntityUtils.toString(entity, Consts.UTF_8);
return JSONObject.parseObject(res); return JSONObject.parseObject(res);
} catch (IOException e) { } catch (Exception e) {
logger.error("数据初始化异常", e); logger.error("获取初始化数据异常", e);
return null; return null;
} }
} }
@ -339,6 +308,7 @@ public class WebWeixinApi {
String skey, String skey,
String wxuin, String wxuin,
String loginUserName) { String loginUserName) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.statusnotify_url")) String url = new ST(PropertiesUtil.getProperty("webwx-url.statusnotify_url"))
.add("pass_ticket", passticket) .add("pass_ticket", passticket)
.render(); .render();
@ -356,17 +326,17 @@ public class WebWeixinApi {
HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8); HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8);
httpPost.setEntity(paramEntity); httpPost.setEntity(paramEntity);
try {
HttpResponse response = httpClient.execute(httpPost); HttpResponse response = httpClient.execute(httpPost);
if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) { int statusCode = response.getStatusLine().getStatusCode();
throw new RuntimeException("请求错误"); if (HttpStatus.SC_OK != statusCode) {
throw new RuntimeException("响应失败(" + statusCode + ")");
} }
HttpEntity entity = response.getEntity(); HttpEntity entity = response.getEntity();
String res = EntityUtils.toString(entity, Consts.UTF_8); String res = EntityUtils.toString(entity, Consts.UTF_8);
return JSONObject.parseObject(res); return JSONObject.parseObject(res);
} catch (IOException e) { } catch (Exception e) {
logger.error("开启消息状态通知异常", e); logger.error("开启消息状态通知异常", e);
return null; return null;
} }
@ -380,14 +350,15 @@ public class WebWeixinApi {
String skey, String skey,
String wxuin, String wxuin,
JSONArray SyncKeyList) { JSONArray SyncKeyList) {
try {
long millis = System.currentTimeMillis(); long millis = System.currentTimeMillis();
String url = new ST(PropertiesUtil.getProperty("webwx-url.synccheck_url")) String url = new ST(PropertiesUtil.getProperty("webwx-url.synccheck_url"))
.add("r", millis) .add("r", millis)
.add("skey", StringUtil.encodeURL(skey, "UTF-8")) .add("skey", StringUtil.encodeURL(skey, Consts.UTF_8.name()))
.add("sid", wxsid) .add("sid", wxsid)
.add("uin", wxuin) .add("uin", wxuin)
.add("deviceid", WechatUtil.createDeviceID()) .add("deviceid", WechatUtil.createDeviceID())
.add("synckey", StringUtil.encodeURL(WechatUtil.syncKeyListToString(SyncKeyList), "UTF-8")) .add("synckey", StringUtil.encodeURL(WechatUtil.syncKeyListToString(SyncKeyList), Consts.UTF_8.name()))
.add("_", millis) .add("_", millis)
.render(); .render();
@ -395,19 +366,19 @@ public class WebWeixinApi {
httpGet.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent")); httpGet.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent"));
httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build()); httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build());
try {
HttpResponse response = httpClient.execute(httpGet); HttpResponse response = httpClient.execute(httpGet);
if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) { int statusCode = response.getStatusLine().getStatusCode();
throw new RuntimeException("请求错误"); if (HttpStatus.SC_OK != statusCode) {
throw new RuntimeException("响应失败(" + statusCode + ")");
} }
HttpEntity entity = response.getEntity(); HttpEntity entity = response.getEntity();
String res = EntityUtils.toString(entity); String res = EntityUtils.toString(entity, Consts.UTF_8);
String regExp = "window.synccheck=\\{retcode:\"(\\d+)\",selector:\"(\\d+)\"}"; String regExp = "window.synccheck=\\{retcode:\"(\\d+)\",selector:\"(\\d+)\"}";
Matcher matcher = Pattern.compile(regExp).matcher(res); Matcher matcher = Pattern.compile(regExp).matcher(res);
if (!matcher.find()) { if (!matcher.find()) {
throw new RuntimeException("服务端状态同步失败"); throw new RuntimeException("返回数据错误");
} }
JSONObject result = new JSONObject(); JSONObject result = new JSONObject();
@ -415,7 +386,7 @@ public class WebWeixinApi {
result.put("selector", matcher.group(2)); result.put("selector", matcher.group(2));
return result; return result;
} catch (IOException e) { } catch (Exception e) {
logger.error("服务端状态同步异常", e); logger.error("服务端状态同步异常", e);
return null; return null;
} }
@ -427,27 +398,27 @@ public class WebWeixinApi {
public JSONObject getContact(HttpClient httpClient, public JSONObject getContact(HttpClient httpClient,
String passticket, String passticket,
String skey) { String skey) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.getcontact_url")) String url = new ST(PropertiesUtil.getProperty("webwx-url.getcontact_url"))
.add("pass_ticket", StringUtil.encodeURL(passticket, "UTF-8")) .add("pass_ticket", StringUtil.encodeURL(passticket, Consts.UTF_8.name()))
.add("r", System.currentTimeMillis()) .add("r", System.currentTimeMillis())
.add("skey", StringUtil.encodeURL(skey, "UTF-8")) .add("skey", StringUtil.encodeURL(skey, Consts.UTF_8.name()))
.render(); .render();
HttpGet httpGet = new HttpGet(url); HttpGet httpGet = new HttpGet(url);
httpGet.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent")); httpGet.setHeader("User-Agent", PropertiesUtil.getProperty("wechat4j.userAgent"));
httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build()); httpGet.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build());
try {
HttpResponse response = httpClient.execute(httpGet); HttpResponse response = httpClient.execute(httpGet);
if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) { int statusCode = response.getStatusLine().getStatusCode();
throw new RuntimeException("请求错误"); if (HttpStatus.SC_OK != statusCode) {
throw new RuntimeException("响应失败(" + statusCode + ")");
} }
HttpEntity entity = response.getEntity(); HttpEntity entity = response.getEntity();
String res = EntityUtils.toString(entity); String res = EntityUtils.toString(entity, Consts.UTF_8);
return JSONObject.parseObject(res); return JSONObject.parseObject(res);
} catch (IOException e) { } catch (Exception e) {
logger.error("获取全部联系人列表异常", e); logger.error("获取全部联系人列表异常", e);
return null; return null;
} }
@ -462,8 +433,9 @@ public class WebWeixinApi {
String skey, String skey,
String wxuin, String wxuin,
JSONArray batchContactList) { JSONArray batchContactList) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.batchgetcontact_url")) String url = new ST(PropertiesUtil.getProperty("webwx-url.batchgetcontact_url"))
.add("pass_ticket", StringUtil.encodeURL(passticket, "UTF-8")) .add("pass_ticket", StringUtil.encodeURL(passticket, Consts.UTF_8.name()))
.add("r", System.currentTimeMillis()) .add("r", System.currentTimeMillis())
.render(); .render();
@ -478,17 +450,17 @@ public class WebWeixinApi {
HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8); HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8);
httpPost.setEntity(paramEntity); httpPost.setEntity(paramEntity);
try {
HttpResponse response = httpClient.execute(httpPost); HttpResponse response = httpClient.execute(httpPost);
if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) { int statusCode = response.getStatusLine().getStatusCode();
throw new RuntimeException("请求错误"); if (HttpStatus.SC_OK != statusCode) {
throw new RuntimeException("响应失败(" + statusCode + ")");
} }
HttpEntity entity = response.getEntity(); HttpEntity entity = response.getEntity();
String res = EntityUtils.toString(entity); String res = EntityUtils.toString(entity, Consts.UTF_8);
return JSONObject.parseObject(res); return JSONObject.parseObject(res);
} catch (IOException e) { } catch (Exception e) {
logger.error("批量获取指定联系人信息异常", e); logger.error("批量获取指定联系人信息异常", e);
return null; return null;
} }
@ -503,6 +475,7 @@ public class WebWeixinApi {
String skey, String skey,
String wxuin, String wxuin,
JSONObject SyncKey) { JSONObject SyncKey) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.webwxsync_url")) String url = new ST(PropertiesUtil.getProperty("webwx-url.webwxsync_url"))
.add("skey", skey) .add("skey", skey)
.add("sid", wxsid) .add("sid", wxsid)
@ -519,18 +492,18 @@ public class WebWeixinApi {
HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8); HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8);
httpPost.setEntity(paramEntity); httpPost.setEntity(paramEntity);
try {
HttpResponse response = httpClient.execute(httpPost); HttpResponse response = httpClient.execute(httpPost);
if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) { int statusCode = response.getStatusLine().getStatusCode();
throw new RuntimeException("请求错误"); if (HttpStatus.SC_OK != statusCode) {
throw new RuntimeException("响应失败(" + statusCode + ")");
} }
HttpEntity entity = response.getEntity(); HttpEntity entity = response.getEntity();
String res = EntityUtils.toString(entity, Consts.UTF_8); String res = EntityUtils.toString(entity, Consts.UTF_8);
return JSONObject.parseObject(res); return JSONObject.parseObject(res);
} catch (IOException e) { } catch (Exception e) {
logger.error("开启消息状态通知异常", e); logger.error("从服务端拉取新消息异常", e);
return null; return null;
} }
} }
@ -547,6 +520,7 @@ public class WebWeixinApi {
int Type, int Type,
String FromUserName, String FromUserName,
String ToUserName) { String ToUserName) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.webwxsendmsg_url")) String url = new ST(PropertiesUtil.getProperty("webwx-url.webwxsendmsg_url"))
.add("pass_ticket", passticket) .add("pass_ticket", passticket)
.render(); .render();
@ -562,10 +536,10 @@ public class WebWeixinApi {
HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8); HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8);
httpPost.setEntity(paramEntity); httpPost.setEntity(paramEntity);
try {
HttpResponse response = httpClient.execute(httpPost); HttpResponse response = httpClient.execute(httpPost);
if (HttpStatus.SC_OK != response.getStatusLine().getStatusCode()) { int statusCode = response.getStatusLine().getStatusCode();
throw new RuntimeException("请求错误"); if (HttpStatus.SC_OK != statusCode) {
throw new RuntimeException("响应失败(" + statusCode + ")");
} }
HttpEntity entity = response.getEntity(); HttpEntity entity = response.getEntity();
@ -574,8 +548,8 @@ public class WebWeixinApi {
JSONObject result = JSONObject.parseObject(res); JSONObject result = JSONObject.parseObject(res);
return result; return result;
} catch (IOException e) { } catch (Exception e) {
logger.error("开启消息状态通知异常", e); logger.error("发送消息异常", e);
return null; return null;
} }
} }

View File

@ -0,0 +1,28 @@
package com.hotlcc.wechat4j.enums;
/**
* 等待确认登录的tip
*
* @author https://gitee.com/hotlcc
*/
public enum LoginTipEnum {
TIP_0(0, "扫码登录"),
TIP_1(1, "确认登录");
private int code;
private String desc;
LoginTipEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() {
return code;
}
@Override
public String toString() {
return code + "";
}
}

View File

@ -0,0 +1,38 @@
package com.hotlcc.wechat4j.enums;
/**
* 操作系统enum
*
* @author https://gitee.com/hotlcc
*/
public enum OperatingSystemEnum {
DARWIN("darwin"),
WINDOWS("windows"),
LINUX("linux"),
MAC_OS("mac"),
OTHER("other");
private String value;
public String getValue() {
return value;
}
OperatingSystemEnum(String value) {
this.value = value;
}
public static OperatingSystemEnum currentOperatingSystem() {
String osName = System.getProperty("os.name").toLowerCase();
if (osName.indexOf(OperatingSystemEnum.DARWIN.getValue()) >= 0) {
return OperatingSystemEnum.DARWIN;
} else if (osName.indexOf(OperatingSystemEnum.WINDOWS.getValue()) >= 0) {
return OperatingSystemEnum.WINDOWS;
} else if (osName.indexOf(OperatingSystemEnum.LINUX.getValue()) >= 0) {
return OperatingSystemEnum.LINUX;
} else if (osName.indexOf(OperatingSystemEnum.MAC_OS.getValue()) >= 0) {
return OperatingSystemEnum.MAC_OS;
}
return OperatingSystemEnum.OTHER;
}
}

View File

@ -6,10 +6,15 @@ import com.google.zxing.NotFoundException;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource; import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.BitMatrix; import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer; import com.google.zxing.common.HybridBinarizer;
import com.hotlcc.wechat4j.enums.OperatingSystemEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -21,6 +26,8 @@ import java.util.Set;
* @author Allen * @author Allen
*/ */
public final class QRCodeUtil { public final class QRCodeUtil {
private static Logger logger = LoggerFactory.getLogger(QRCodeUtil.class);
private QRCodeUtil() { private QRCodeUtil() {
} }
@ -227,4 +234,65 @@ public final class QRCodeUtil {
public static String toCharMatrix(byte[] data) { public static String toCharMatrix(byte[] data) {
return toCharMatrix(data, " ", "██"); return toCharMatrix(data, " ", "██");
} }
/**
* 将二维码图片数据写入到临时文件
*
* @param data
* @return
*/
public static File writeToTempFile(byte[] data) {
FileOutputStream fos = null;
try {
File tmp = File.createTempFile(PropertiesUtil.getProperty("wechat4j.qrcode.tmpfile.prefix"), ".jpg");
fos = new FileOutputStream(tmp);
fos.write(data);
fos.flush();
return tmp;
} catch (IOException e) {
logger.error("二维码写入临时文件异常", e);
throw new RuntimeException(e);
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 打开二维码图片
*
* @param data
*/
public static void openQRCodeImage(byte[] data) {
OperatingSystemEnum os = OperatingSystemEnum.currentOperatingSystem();
Runtime runtime = null;
File tmp = null;
switch (os) {
case WINDOWS:
runtime = Runtime.getRuntime();
tmp = writeToTempFile(data);
try {
runtime.exec("cmd /c start " + tmp.getPath());
} catch (Exception e) {
e.printStackTrace();
}
break;
case MAC_OS:
runtime = Runtime.getRuntime();
tmp = writeToTempFile(data);
try {
runtime.exec("open " + tmp.getPath());
} catch (Exception e) {
e.printStackTrace();
}
break;
default:
break;
}
}
} }

View File

@ -2,3 +2,5 @@
webwx.appid=wx782c26e4c19acffb webwx.appid=wx782c26e4c19acffb
# httpclient的UserAgent # 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 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_

View File

@ -4,7 +4,7 @@ webwx-url.uuid_url=https://login.wx2.qq.com/jslogin?appid=<appid>&redirect_uri=h
## 1.2、获取二维码 ## 1.2、获取二维码
webwx-url.qrcode_url=https://login.weixin.qq.com/qrcode/<uuid> webwx-url.qrcode_url=https://login.weixin.qq.com/qrcode/<uuid>
## 1.3、等待扫码登录并获取跳转url ## 1.3、等待扫码登录并获取跳转url
webwx-url.redirect_uri=https://login.wx2.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=<uuid>&tip=0&r=<r>&_=<_> webwx-url.redirect_uri=https://login.wx2.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=<uuid>&tip=<tip>&r=<r>&_=<_>
## 1.4、获取登录认证码 ## 1.4、获取登录认证码
webwx-url.newlogin_url=<redirectUri>&fun=new&version=v2 webwx-url.newlogin_url=<redirectUri>&fun=new&version=v2
## 1.5、退出登录 ## 1.5、退出登录