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

提交代码

This commit is contained in:
hotlcc 2018-07-25 20:33:31 +08:00
parent 7ec5dbfce3
commit 342a8ed5c9
3 changed files with 132 additions and 67 deletions

View File

@ -55,19 +55,21 @@ public class Wechat {
private volatile String passTicket;
private volatile String skey;
private volatile String wxuin;
//url版本号
private volatile String urlVersion;
//用户数据
private volatile UserInfo loginUser;
private final Lock loginUserLock = new ReentrantLock();
private volatile JSONObject SyncKey;
private final Lock SyncKeyLock = new ReentrantLock();
private volatile List<UserInfo> ContactList;
private final Lock ContactListLock = new ReentrantLock();
private volatile JSONObject syncKey;
private final Lock syncKeyLock = new ReentrantLock();
private volatile List<UserInfo> contactList;
private final Lock contactListLock = new ReentrantLock();
//在线状态
private volatile boolean isOnline = false;
private final Lock isOnlineLock = new ReentrantLock();
//同步监听器
private volatile SyncMonitor syncMonitor;
//退出事件处理器
private List<ExitEventHandler> exitEventHandlers;
//接收消息处理器
@ -274,13 +276,12 @@ public class Wechat {
*
* @return
*/
private String waitForConfirm(PrintStream ps, String uuid) {
private JSONObject waitForConfirm(PrintStream ps, String uuid) {
ps.print("等待手机端扫码...");
ps.flush();
String code = null;
boolean flag = false;
while (!"200".equals(code)) {
while (true) {
JSONObject result = webWeixinApi.getRedirectUri(httpClient, LoginTipEnum.TIP_0, uuid);
if (result == null) {
ps.println("\t失败出现异常");
@ -288,7 +289,7 @@ public class Wechat {
return null;
}
code = result.getString("code");
String code = result.getString("code");
if ("408".equals(code)) {
ps.print(".");
ps.flush();
@ -306,15 +307,13 @@ public class Wechat {
}
continue;
} else if ("200".equals(code)) {
String redirectUri = result.getString("redirectUri");
ps.println("\t成功认证完成");
ps.flush();
return redirectUri;
return result;
} else {
return null;
}
}
return null;
}
/**
@ -360,7 +359,7 @@ public class Wechat {
ps.print("尝试push方式获取uuid...");
ps.flush();
JSONObject result = webWeixinApi.pushLogin(httpClient, wxuin);
JSONObject result = webWeixinApi.pushLogin(httpClient, urlVersion, wxuin);
if (result == null) {
ps.println("\t失败出现异常");
ps.flush();
@ -393,7 +392,7 @@ public class Wechat {
* @return
*/
private boolean wxInit() {
JSONObject result = webWeixinApi.webWeixinInit(httpClient, passTicket, new BaseRequest(wxsid, skey, wxuin));
JSONObject result = webWeixinApi.webWeixinInit(httpClient, urlVersion, passTicket, new BaseRequest(wxsid, skey, wxuin));
if (result == null) {
return false;
}
@ -409,7 +408,7 @@ public class Wechat {
}
loginUser = UserInfo.valueOf(result.getJSONObject("User"));
SyncKey = result.getJSONObject("SyncKey");
syncKey = result.getJSONObject("SyncKey");
return true;
}
@ -457,7 +456,7 @@ public class Wechat {
*/
private boolean statusNotify(int time) {
for (int i = 0; i < time; i++) {
JSONObject result = webWeixinApi.statusNotify(httpClient, passTicket, new BaseRequest(wxsid, skey, wxuin), getLoginUserName(false));
JSONObject result = webWeixinApi.statusNotify(httpClient, urlVersion, passTicket, new BaseRequest(wxsid, skey, wxuin), getLoginUserName(false));
if (result == null) {
continue;
}
@ -481,7 +480,7 @@ public class Wechat {
/**
* 自动登录
*/
public boolean autoLogin(OutputStream os) {
public boolean autoLogin(OutputStream os, boolean tryPushLogin) {
// 0获取消息打印流
PrintStream ps = null;
if (os != null) {
@ -502,7 +501,7 @@ public class Wechat {
// 2登录
// 2.1获取uuid
String uuid = null;
if (StringUtil.isNotEmpty(wxuin)) {
if (tryPushLogin && StringUtil.isNotEmpty(wxuin)) {
uuid = getWxUuid(ps, wxuin);
}
if (StringUtil.isEmpty(uuid)) {
@ -520,14 +519,15 @@ public class Wechat {
return false;
}
// 2.3等待确认
String redirectUri = waitForConfirm(ps, uuid);
if (StringUtil.isEmpty(redirectUri)) {
result = waitForConfirm(ps, uuid);
if (result == null) {
ps.println("手机端认证失败,登录不成功");
ps.flush();
return false;
}
urlVersion = result.getString("urlVersion");
// 2.4获取登录认证码
if (!getLoginCode(ps, redirectUri)) {
if (!getLoginCode(ps, result.getString("redirectUri"))) {
ps.println("无法获取登录认证码,登录不成功");
ps.flush();
return false;
@ -562,23 +562,57 @@ public class Wechat {
* @return
*/
public boolean autoLogin() {
return autoLogin(null);
return autoLogin(null, false);
}
/**
* 退出登录
*/
public void logout() {
public void logout(boolean clearAllLoginInfo) {
try {
isOnlineLock.lock();
webWeixinApi.logout(httpClient, new BaseRequest(wxsid, skey, wxuin));
webWeixinApi.logout(httpClient, urlVersion, new BaseRequest(wxsid, skey, wxuin));
isOnline = false;
if (clearAllLoginInfo) {
clearAllLoginInfo();
}
} finally {
isOnlineLock.unlock();
}
}
public void logout() {
logout(true);
}
/**
* 清除全部登录信息
*/
private void clearAllLoginInfo() {
try {
loginUserLock.lock();
syncKeyLock.lock();
contactListLock.lock();
wxsid = null;
passTicket = null;
skey = null;
urlVersion = null;
loginUser = null;
syncKey = null;
if (contactList != null) {
contactList.clear();
contactList = null;
}
} finally {
loginUserLock.unlock();
syncKeyLock.unlock();
contactListLock.unlock();
}
}
/**
* 判断在线状态
*
@ -607,7 +641,7 @@ public class Wechat {
try {
//API调用异常导致退出
JSONObject result = webWeixinApi.syncCheck(httpClient, new BaseRequest(wxsid, skey, wxuin), getSyncKeyList(false));
JSONObject result = webWeixinApi.syncCheck(httpClient, urlVersion, new BaseRequest(wxsid, skey, wxuin), getSyncKeyList(false));
logger.debug("微信同步监听心跳返回数据:{}", result);
if (result == null) {
throw new RuntimeException("微信API调用异常");
@ -738,7 +772,7 @@ public class Wechat {
*/
private void webWxSync() {
try {
JSONObject result = webWeixinApi.webWxSync(httpClient, passTicket, new BaseRequest(wxsid, skey, wxuin), SyncKey);
JSONObject result = webWeixinApi.webWxSync(httpClient, urlVersion, passTicket, new BaseRequest(wxsid, skey, wxuin), syncKey);
if (result == null) {
logger.error("从服务端同步新数据异常");
return;
@ -762,10 +796,10 @@ public class Wechat {
//更新SyncKey
try {
SyncKeyLock.lock();
SyncKey = result.getJSONObject("SyncKey");
syncKeyLock.lock();
syncKey = result.getJSONObject("SyncKey");
} finally {
SyncKeyLock.unlock();
syncKeyLock.unlock();
}
} catch (Exception e) {
logger.error("Execute webWxSync error.", e);
@ -834,7 +868,7 @@ public class Wechat {
*/
public UserInfo getLoginUser(boolean update) {
if (loginUser == null || update) {
JSONObject result = webWeixinApi.webWeixinInit(httpClient, passTicket, new BaseRequest(wxsid, skey, wxuin));
JSONObject result = webWeixinApi.webWeixinInit(httpClient, urlVersion, passTicket, new BaseRequest(wxsid, skey, wxuin));
if (result == null) {
return loginUser;
}
@ -896,34 +930,34 @@ public class Wechat {
* @return
*/
private JSONObject getSyncKey(boolean update) {
if (SyncKey == null || update) {
JSONObject result = webWeixinApi.webWeixinInit(httpClient, passTicket, new BaseRequest(wxsid, skey, wxuin));
if (syncKey == null || update) {
JSONObject result = webWeixinApi.webWeixinInit(httpClient, urlVersion, passTicket, new BaseRequest(wxsid, skey, wxuin));
if (result == null) {
return SyncKey;
return syncKey;
}
JSONObject BaseResponse = result.getJSONObject("BaseResponse");
if (result == null) {
return SyncKey;
return syncKey;
}
int Ret = BaseResponse.getIntValue("Ret");
if (Ret != 0) {
return SyncKey;
return syncKey;
}
try {
SyncKeyLock.lock();
if (SyncKey == null || update) {
SyncKey = result.getJSONObject("SyncKey");
syncKeyLock.lock();
if (syncKey == null || update) {
syncKey = result.getJSONObject("SyncKey");
}
} finally {
SyncKeyLock.unlock();
syncKeyLock.unlock();
}
return SyncKey;
return syncKey;
}
return SyncKey;
return syncKey;
}
/**
@ -947,34 +981,34 @@ public class Wechat {
* @return
*/
public List<UserInfo> getContactList(boolean update) {
if (ContactList == null || update) {
JSONObject result = webWeixinApi.getContact(httpClient, passTicket, skey);
if (contactList == null || update) {
JSONObject result = webWeixinApi.getContact(httpClient, urlVersion, passTicket, skey);
if (result == null) {
return ContactList;
return contactList;
}
JSONObject BaseResponse = result.getJSONObject("BaseResponse");
if (BaseResponse == null) {
return ContactList;
return contactList;
}
String Ret = BaseResponse.getString("Ret");
if (!"0".equals(Ret)) {
return ContactList;
return contactList;
}
try {
ContactListLock.lock();
if (ContactList == null || update) {
ContactList = UserInfo.valueOf(result.getJSONArray("MemberList"));
contactListLock.lock();
if (contactList == null || update) {
contactList = UserInfo.valueOf(result.getJSONArray("MemberList"));
}
} finally {
ContactListLock.unlock();
contactListLock.unlock();
}
return ContactList;
return contactList;
}
return ContactList;
return contactList;
}
/**
@ -1089,7 +1123,7 @@ public class Wechat {
}
message.setType(MsgTypeEnum.TEXT_MSG.getCode());
JSONObject result = webWeixinApi.sendMsg(httpClient, passTicket, baseRequest, message);
JSONObject result = webWeixinApi.sendMsg(httpClient, urlVersion, passTicket, baseRequest, message);
return result;
}
@ -1152,7 +1186,7 @@ public class Wechat {
BaseRequest baseRequest = new BaseRequest(wxsid, skey, wxuin);
String dataTicket = getCookieValue("webwx_data_ticket");
JSONObject result = webWeixinApi.uploadMedia(httpClient, passTicket, baseRequest, loginUserName, toUserName, dataTicket, image);
JSONObject result = webWeixinApi.uploadMedia(httpClient, urlVersion, passTicket, baseRequest, loginUserName, toUserName, dataTicket, image);
return result;
}
}

View File

@ -48,6 +48,7 @@ public class WebWeixinApi {
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_2 = Pattern.compile("window.code=(\\d+);\\s*window.redirect_uri=\"(\\S+?)\";");
private static Pattern PATTERN_REDIRECT_URI_3 = Pattern.compile("http(s*)://wx(\\d*)\\.qq\\.com\\/");
/**
* 获取微信uuid
@ -184,8 +185,16 @@ public class WebWeixinApi {
if (!matcher.find()) {
throw new RuntimeException("没有匹配到跳转uri");
}
String redirectUri = matcher.group(2);
result.put("msg", "手机确认成功");
result.put("redirectUri", matcher.group(2));
result.put("redirectUri", redirectUri);
matcher = PATTERN_REDIRECT_URI_3.matcher(redirectUri);
if (!matcher.find()) {
throw new RuntimeException("从跳转uri中没有匹配到url版本号");
}
String urlVersion = matcher.group(2);
result.put("urlVersion", urlVersion);
} else {
throw new RuntimeException("返回code错误");
}
@ -233,6 +242,7 @@ public class WebWeixinApi {
* 退出登录
*/
public void logout(HttpClient httpClient,
String urlVersion,
BaseRequest BaseRequest) {
try {
List<NameValuePair> pairList = new ArrayList<>();
@ -242,6 +252,7 @@ public class WebWeixinApi {
//分两步进行
for (int i = 0; i <= 1; i++) {
String url = new ST(PropertiesUtil.getProperty("webwx-url.logout_url"))
.add("urlVersion", urlVersion)
.add("type", i)
.add("skey", StringUtil.encodeURL(BaseRequest.getSkey(), Consts.UTF_8.name()))
.render();
@ -263,10 +274,12 @@ public class WebWeixinApi {
* push登录
*/
public JSONObject pushLogin(HttpClient httpClient,
String urlVersion,
String wxuin) {
try {
long millis = System.currentTimeMillis();
String url = new ST(PropertiesUtil.getProperty("webwx-url.pushlogin_url"))
.add("urlVersion", urlVersion)
.add("uin", wxuin)
.render();
@ -293,10 +306,12 @@ public class WebWeixinApi {
* 获取初始化数据
*/
public JSONObject webWeixinInit(HttpClient httpClient,
String urlVersion,
String passticket,
BaseRequest BaseRequest) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.webwxinit_url"))
.add("urlVersion", urlVersion)
.add("pass_ticket", passticket)
.add("r", System.currentTimeMillis() / 1252L)
.render();
@ -331,11 +346,13 @@ public class WebWeixinApi {
* @return
*/
public JSONObject statusNotify(HttpClient httpClient,
String urlVersion,
String passticket,
BaseRequest BaseRequest,
String loginUserName) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.statusnotify_url"))
.add("urlVersion", urlVersion)
.add("pass_ticket", passticket)
.render();
@ -371,11 +388,13 @@ public class WebWeixinApi {
* 服务端状态同步心跳
*/
public JSONObject syncCheck(HttpClient httpClient,
String urlVersion,
BaseRequest BaseRequest,
JSONArray SyncKeyList) {
try {
long millis = System.currentTimeMillis();
String url = new ST(PropertiesUtil.getProperty("webwx-url.synccheck_url"))
.add("urlVersion", urlVersion)
.add("r", millis)
.add("skey", StringUtil.encodeURL(BaseRequest.getSkey(), Consts.UTF_8.name()))
.add("sid", BaseRequest.getSid())
@ -421,10 +440,12 @@ public class WebWeixinApi {
* 获取全部联系人列表
*/
public JSONObject getContact(HttpClient httpClient,
String urlVersion,
String passticket,
String skey) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.getcontact_url"))
.add("urlVersion", urlVersion)
.add("pass_ticket", StringUtil.encodeURL(passticket, Consts.UTF_8.name()))
.add("r", System.currentTimeMillis())
.add("skey", StringUtil.encodeURL(skey, Consts.UTF_8.name()))
@ -452,11 +473,13 @@ public class WebWeixinApi {
* 批量获取指定用户信息
*/
public JSONObject batchGetContact(HttpClient httpClient,
String urlVersion,
String passticket,
BaseRequest BaseRequest,
JSONArray batchContactList) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.batchgetcontact_url"))
.add("urlVersion", urlVersion)
.add("pass_ticket", StringUtil.encodeURL(passticket, Consts.UTF_8.name()))
.add("r", System.currentTimeMillis())
.render();
@ -491,11 +514,13 @@ public class WebWeixinApi {
* 从服务端同步新数据
*/
public JSONObject webWxSync(HttpClient httpClient,
String urlVersion,
String passticket,
BaseRequest BaseRequest,
JSONObject SyncKey) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.webwxsync_url"))
.add("urlVersion", urlVersion)
.add("skey", BaseRequest.getSkey())
.add("sid", BaseRequest.getSid())
.add("pass_ticket", passticket)
@ -530,11 +555,13 @@ public class WebWeixinApi {
* 发送消息
*/
public JSONObject sendMsg(HttpClient httpClient,
String urlVersion,
String passticket,
BaseRequest baseRequest,
WxMessage message) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.webwxsendmsg_url"))
.add("urlVersion", urlVersion)
.add("pass_ticket", passticket)
.render();
@ -572,6 +599,7 @@ public class WebWeixinApi {
* @return
*/
public JSONObject uploadMedia(HttpClient httpClient,
String urlVersion,
String passticket,
BaseRequest BaseRequest,
String FromUserName,
@ -582,6 +610,7 @@ public class WebWeixinApi {
ContentType contentType) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.uploadmedia_url"))
.add("urlVersion", urlVersion)
.render();
HttpPost httpPost = new HttpPost(url);
@ -640,6 +669,7 @@ public class WebWeixinApi {
* @return
*/
public JSONObject uploadMedia(HttpClient httpClient,
String urlVersion,
String passticket,
BaseRequest baseRequest,
String fromUserName,
@ -648,6 +678,7 @@ public class WebWeixinApi {
File file) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.uploadmedia_url"))
.add("urlVersion", urlVersion)
.render();
HttpPost httpPost = new HttpPost(url);

View File

@ -1,32 +1,32 @@
# 1、登录
## 1.1、获取微信uuid
webwx-url.uuid_url=https://login.wx2.qq.com/jslogin?appid=<appid>&redirect_uri=https%3A%2F%2Fwx2.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_=<_>
webwx-url.uuid_url=https://login.wx.qq.com/jslogin?appid=<appid>&fun=new&lang=zh_CN&_=<_>
## 1.2、获取二维码
webwx-url.qrcode_url=https://login.weixin.qq.com/qrcode/<uuid>
## 1.3、等待扫码登录并获取跳转url
webwx-url.redirect_uri=https://login.wx2.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=<uuid>&tip=<tip>&r=<r>&_=<_>
webwx-url.redirect_uri=https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=<uuid>&tip=<tip>&r=<r>&_=<_>
## 1.4、获取登录认证码
webwx-url.newlogin_url=<redirectUri>&fun=new&version=v2
## 1.5、退出登录
webwx-url.logout_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxlogout?redirect=1&type=<type>&skey=<skey>
webwx-url.logout_url=https://wx<urlVersion>.qq.com/cgi-bin/mmwebwx-bin/webwxlogout?redirect=1&type=<type>&skey=<skey>
## 1.6、push登录
webwx-url.pushlogin_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxpushloginurl?uin=<uin>
webwx-url.pushlogin_url=https://wx<urlVersion>.qq.com/cgi-bin/mmwebwx-bin/webwxpushloginurl?uin=<uin>
# 2、数据同步
## 2.1、页面初始化
webwx-url.webwxinit_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=<r>&lang=zh_CN&pass_ticket=<pass_ticket>
webwx-url.webwxinit_url=https://wx<urlVersion>.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=<r>&lang=zh_CN&pass_ticket=<pass_ticket>
## 2.2、开启消息状态通知
webwx-url.statusnotify_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxstatusnotify?lang=zh_CN&pass_ticket=<pass_ticket>
webwx-url.statusnotify_url=https://wx<urlVersion>.qq.com/cgi-bin/mmwebwx-bin/webwxstatusnotify?lang=zh_CN&pass_ticket=<pass_ticket>
## 2.3、服务端状态同步
webwx-url.synccheck_url=https://webpush.wx2.qq.com/cgi-bin/mmwebwx-bin/synccheck?r=<r>&skey=<skey>&sid=<sid>&uin=<uin>&deviceid=<deviceid>&synckey=<synckey>&_=<_>
webwx-url.synccheck_url=https://webpush.wx<urlVersion>.qq.com/cgi-bin/mmwebwx-bin/synccheck?r=<r>&skey=<skey>&sid=<sid>&uin=<uin>&deviceid=<deviceid>&synckey=<synckey>&_=<_>
# 3、联系人管理
## 3.1、获取全部联系人列表
webwx-url.getcontact_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&pass_ticket=<pass_ticket>&r=<r>&seq=0&skey=<skey>
webwx-url.getcontact_url=https://wx<urlVersion>.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&pass_ticket=<pass_ticket>&r=<r>&seq=0&skey=<skey>
## 3.2、批量获取指定联系人列表
webwx-url.batchgetcontact_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxbatchgetcontact?type=ex&r=<r>&lang=zh_CN&pass_ticket=<pass_ticket>
webwx-url.batchgetcontact_url=https://wx<urlVersion>.qq.com/cgi-bin/mmwebwx-bin/webwxbatchgetcontact?type=ex&r=<r>&lang=zh_CN&pass_ticket=<pass_ticket>
# 4、收发消息
## 4.1、从服务端拉取新消息
webwx-url.webwxsync_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=<sid>&skey=<skey>&pass_ticket=<pass_ticket>
webwx-url.webwxsync_url=https://wx<urlVersion>.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=<sid>&skey=<skey>&pass_ticket=<pass_ticket>
## 4.2、发送消息
webwx-url.webwxsendmsg_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket=<pass_ticket>
webwx-url.webwxsendmsg_url=https://wx<urlVersion>.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket=<pass_ticket>
## 4.3、上传媒体文件
webwx-url.uploadmedia_url=https://file.wx2.qq.com/cgi-bin/mmwebwx-bin/webwxuploadmedia?f=json
webwx-url.uploadmedia_url=https://file.wx<urlVersion>.qq.com/cgi-bin/mmwebwx-bin/webwxuploadmedia?f=json