2
0
mirror of https://gitee.com/hotlcc/wechat4j.git synced 2025-06-15 14:56:59 +08:00

提交代码

This commit is contained in:
hotlcc 2018-07-25 14:46:45 +08:00
parent acc3fc9966
commit 1e028d62ed
7 changed files with 321 additions and 88 deletions

View File

@ -3,18 +3,14 @@ package com.hotlcc.wechat4j;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hotlcc.wechat4j.api.WebWeixinApi;
import com.hotlcc.wechat4j.enums.ExitTypeEnum;
import com.hotlcc.wechat4j.enums.LoginTipEnum;
import com.hotlcc.wechat4j.enums.RetcodeEnum;
import com.hotlcc.wechat4j.enums.SelectorEnum;
import com.hotlcc.wechat4j.enums.*;
import com.hotlcc.wechat4j.handler.ExitEventHandler;
import com.hotlcc.wechat4j.handler.ReceivedMsgHandler;
import com.hotlcc.wechat4j.model.BaseRequest;
import com.hotlcc.wechat4j.model.ReceivedMsg;
import com.hotlcc.wechat4j.model.UserInfo;
import com.hotlcc.wechat4j.util.CommonUtil;
import com.hotlcc.wechat4j.util.PropertiesUtil;
import com.hotlcc.wechat4j.util.QRCodeUtil;
import com.hotlcc.wechat4j.util.StringUtil;
import com.hotlcc.wechat4j.model.WxMessage;
import com.hotlcc.wechat4j.util.*;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
@ -374,7 +370,7 @@ public class Wechat {
* @return
*/
private boolean wxInit() {
JSONObject result = webWeixinApi.webWeixinInit(httpClient, passTicket, wxsid, skey, wxuin);
JSONObject result = webWeixinApi.webWeixinInit(httpClient, passTicket, new BaseRequest(wxsid, skey, wxuin));
if (result == null) {
return false;
}
@ -438,7 +434,7 @@ public class Wechat {
*/
private boolean statusNotify(int time) {
for (int i = 0; i < time; i++) {
JSONObject result = webWeixinApi.statusNotify(httpClient, passTicket, wxsid, skey, wxuin, getLoginUserName(false));
JSONObject result = webWeixinApi.statusNotify(httpClient, passTicket, new BaseRequest(wxsid, skey, wxuin), getLoginUserName(false));
if (result == null) {
continue;
}
@ -553,7 +549,7 @@ public class Wechat {
try {
isOnlineLock.lock();
webWeixinApi.logout(httpClient, wxsid, skey, wxuin);
webWeixinApi.logout(httpClient, new BaseRequest(wxsid, skey, wxuin));
isOnline = false;
} finally {
isOnlineLock.unlock();
@ -588,7 +584,7 @@ public class Wechat {
try {
//API调用异常导致退出
JSONObject result = webWeixinApi.syncCheck(httpClient, wxsid, skey, wxuin, getSyncKeyList(false));
JSONObject result = webWeixinApi.syncCheck(httpClient, new BaseRequest(wxsid, skey, wxuin), getSyncKeyList(false));
logger.debug("微信同步监听心跳返回数据:{}", result);
if (result == null) {
throw new RuntimeException("微信API调用异常");
@ -719,7 +715,7 @@ public class Wechat {
*/
private void webWxSync() {
try {
JSONObject result = webWeixinApi.webWxSync(httpClient, passTicket, wxsid, skey, wxuin, SyncKey);
JSONObject result = webWeixinApi.webWxSync(httpClient, passTicket, new BaseRequest(wxsid, skey, wxuin), SyncKey);
if (result == null) {
logger.error("从服务端同步新数据异常");
return;
@ -815,7 +811,7 @@ public class Wechat {
*/
public UserInfo getLoginUser(boolean update) {
if (loginUser == null || update) {
JSONObject result = webWeixinApi.webWeixinInit(httpClient, passTicket, wxsid, skey, wxuin);
JSONObject result = webWeixinApi.webWeixinInit(httpClient, passTicket, new BaseRequest(wxsid, skey, wxuin));
if (result == null) {
return loginUser;
}
@ -878,7 +874,7 @@ public class Wechat {
*/
private JSONObject getSyncKey(boolean update) {
if (SyncKey == null || update) {
JSONObject result = webWeixinApi.webWeixinInit(httpClient, passTicket, wxsid, skey, wxuin);
JSONObject result = webWeixinApi.webWeixinInit(httpClient, passTicket, new BaseRequest(wxsid, skey, wxuin));
if (result == null) {
return SyncKey;
}
@ -1047,4 +1043,81 @@ public class Wechat {
return null;
}
/**
* 发送文本消息
*
* @return
*/
public JSONObject sendText(String Content, String ToUserName) {
BaseRequest BaseRequest = new BaseRequest(wxsid, skey, wxuin);
String msgId = WechatUtil.createMsgId();
String loginUserName = getLoginUserName(false);
WxMessage message = new WxMessage();
message.setClientMsgId(msgId);
message.setContent(Content);
message.setFromUserName(loginUserName);
message.setLocalID(msgId);
if (StringUtil.isEmpty(ToUserName)) {
message.setToUserName(loginUserName);
} else {
message.setToUserName(ToUserName);
}
message.setType(MsgTypeEnum.TEXT_MSG.getCode());
JSONObject result = webWeixinApi.sendMsg(httpClient, passTicket, BaseRequest, message);
return result;
}
/**
* 发送文本消息根据昵称
*
* @param Content
* @param NickName
* @return
*/
public JSONObject sendTextToNickName(String Content, String NickName) {
if (StringUtil.isEmpty(NickName)) {
return sendText(Content, null);
}
UserInfo userInfo = getContactByNickName(false, NickName);
if (userInfo == null) {
return null;
}
String UserName = userInfo.getUserName();
if (StringUtil.isEmpty(UserName)) {
return null;
}
return sendText(Content, UserName);
}
/**
* 发送文本消息根据备注名
*
* @param Content
* @param RemarkName
* @return
*/
public JSONObject sendTextToRemarkName(String Content, String RemarkName) {
if (StringUtil.isEmpty(RemarkName)) {
return sendText(Content, null);
}
UserInfo userInfo = getContactByRemarkName(false, RemarkName);
if (userInfo == null) {
return null;
}
String UserName = userInfo.getUserName();
if (StringUtil.isEmpty(UserName)) {
return null;
}
return sendText(Content, UserName);
}
}

View File

@ -3,9 +3,12 @@ package com.hotlcc.wechat4j.api;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hotlcc.wechat4j.enums.LoginTipEnum;
import com.hotlcc.wechat4j.model.BaseRequest;
import com.hotlcc.wechat4j.model.WxMessage;
import com.hotlcc.wechat4j.util.PropertiesUtil;
import com.hotlcc.wechat4j.util.StringUtil;
import com.hotlcc.wechat4j.util.WechatUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.*;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
@ -14,6 +17,8 @@ import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.json.XML;
@ -225,19 +230,17 @@ public class WebWeixinApi {
* 退出登录
*/
public void logout(HttpClient httpClient,
String wxsid,
String skey,
String wxuin) {
BaseRequest BaseRequest) {
try {
List<NameValuePair> pairList = new ArrayList<>();
pairList.add(new BasicNameValuePair("sid", wxsid));
pairList.add(new BasicNameValuePair("uin", wxuin));
pairList.add(new BasicNameValuePair("sid", BaseRequest.getSid()));
pairList.add(new BasicNameValuePair("uin", BaseRequest.getUin()));
//分两步进行
for (int i = 0; i <= 1; i++) {
String url = new ST(PropertiesUtil.getProperty("webwx-url.logout_url"))
.add("type", i)
.add("skey", StringUtil.encodeURL(skey, Consts.UTF_8.name()))
.add("skey", StringUtil.encodeURL(BaseRequest.getSkey(), Consts.UTF_8.name()))
.render();
HttpPost httpPost = new HttpPost(url);
@ -288,9 +291,7 @@ public class WebWeixinApi {
*/
public JSONObject webWeixinInit(HttpClient httpClient,
String passticket,
String wxsid,
String skey,
String wxuin) {
BaseRequest BaseRequest) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.webwxinit_url"))
.add("pass_ticket", passticket)
@ -301,7 +302,7 @@ public class WebWeixinApi {
httpPost.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
JSONObject paramJson = new JSONObject();
paramJson.put("BaseRequest", WechatUtil.createBaseRequest(wxsid, skey, wxuin));
paramJson.put("BaseRequest", BaseRequest);
HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8);
httpPost.setEntity(paramEntity);
@ -328,9 +329,7 @@ public class WebWeixinApi {
*/
public JSONObject statusNotify(HttpClient httpClient,
String passticket,
String wxsid,
String skey,
String wxuin,
BaseRequest BaseRequest,
String loginUserName) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.statusnotify_url"))
@ -341,7 +340,7 @@ public class WebWeixinApi {
httpPost.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
JSONObject paramJson = new JSONObject();
paramJson.put("BaseRequest", WechatUtil.createBaseRequest(wxsid, skey, wxuin));
paramJson.put("BaseRequest", BaseRequest);
paramJson.put("ClientMsgId", System.currentTimeMillis());
paramJson.put("Code", 3);
paramJson.put("FromUserName", loginUserName);
@ -369,17 +368,15 @@ public class WebWeixinApi {
* 服务端状态同步心跳
*/
public JSONObject syncCheck(HttpClient httpClient,
String wxsid,
String skey,
String wxuin,
BaseRequest BaseRequest,
JSONArray SyncKeyList) {
try {
long millis = System.currentTimeMillis();
String url = new ST(PropertiesUtil.getProperty("webwx-url.synccheck_url"))
.add("r", millis)
.add("skey", StringUtil.encodeURL(skey, Consts.UTF_8.name()))
.add("sid", wxsid)
.add("uin", wxuin)
.add("skey", StringUtil.encodeURL(BaseRequest.getSkey(), Consts.UTF_8.name()))
.add("sid", BaseRequest.getSid())
.add("uin", BaseRequest.getUin())
.add("deviceid", WechatUtil.createDeviceID())
.add("synckey", StringUtil.encodeURL(WechatUtil.syncKeyListToString(SyncKeyList), Consts.UTF_8.name()))
.add("_", millis)
@ -453,9 +450,7 @@ public class WebWeixinApi {
*/
public JSONObject batchGetContact(HttpClient httpClient,
String passticket,
String wxsid,
String skey,
String wxuin,
BaseRequest BaseRequest,
JSONArray batchContactList) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.batchgetcontact_url"))
@ -467,7 +462,7 @@ public class WebWeixinApi {
httpPost.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
JSONObject paramJson = new JSONObject();
paramJson.put("BaseRequest", WechatUtil.createBaseRequest(wxsid, skey, wxuin));
paramJson.put("BaseRequest", BaseRequest);
paramJson.put("Count", batchContactList.size());
paramJson.put("List", batchContactList);
HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8);
@ -494,14 +489,12 @@ public class WebWeixinApi {
*/
public JSONObject webWxSync(HttpClient httpClient,
String passticket,
String wxsid,
String skey,
String wxuin,
BaseRequest BaseRequest,
JSONObject SyncKey) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.webwxsync_url"))
.add("skey", skey)
.add("sid", wxsid)
.add("skey", BaseRequest.getSkey())
.add("sid", BaseRequest.getSid())
.add("pass_ticket", passticket)
.render();
@ -509,7 +502,7 @@ public class WebWeixinApi {
httpPost.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
JSONObject paramJson = new JSONObject();
paramJson.put("BaseRequest", WechatUtil.createBaseRequest(wxsid, skey, wxuin));
paramJson.put("BaseRequest", BaseRequest);
paramJson.put("SyncKey", SyncKey);
HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8);
httpPost.setEntity(paramEntity);
@ -535,13 +528,8 @@ public class WebWeixinApi {
*/
public JSONObject sendMsg(HttpClient httpClient,
String passticket,
String wxsid,
String skey,
String wxuin,
String Content,
int Type,
String FromUserName,
String ToUserName) {
BaseRequest BaseRequest,
WxMessage message) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.webwxsendmsg_url"))
.add("pass_ticket", passticket)
@ -551,8 +539,8 @@ public class WebWeixinApi {
httpPost.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
JSONObject paramJson = new JSONObject();
paramJson.put("BaseRequest", WechatUtil.createBaseRequest(wxsid, skey, wxuin));
paramJson.put("Msg", WechatUtil.createSendMsg(Content, Type, FromUserName, ToUserName));
paramJson.put("BaseRequest", BaseRequest);
paramJson.put("Msg", message);
paramJson.put("Scene", 0);
HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8);
httpPost.setEntity(paramEntity);
@ -574,4 +562,72 @@ public class WebWeixinApi {
return null;
}
}
/**
* 上传媒体文件
*
* @return
*/
public JSONObject uploadMedia(HttpClient httpClient,
String passticket,
BaseRequest BaseRequest,
String FromUserName,
String ToUserName,
String dataTicket,
byte[] data,
String fileName,
ContentType contentType) {
try {
String url = new ST(PropertiesUtil.getProperty("webwx-url.uploadmedia_url"))
.render();
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("Content-type", ContentType.MULTIPART_FORM_DATA.toString());
long millis = System.currentTimeMillis();
JSONObject uploadmediarequest = new JSONObject();
uploadmediarequest.put("UploadType", 2);
uploadmediarequest.put("BaseRequest", BaseRequest);
uploadmediarequest.put("ClientMediaId", millis);
uploadmediarequest.put("TotalLen", data.length);
uploadmediarequest.put("StartPos", 0);
uploadmediarequest.put("DataLen", data.length);
uploadmediarequest.put("MediaType", 4);
uploadmediarequest.put("FromUserName", FromUserName);
uploadmediarequest.put("ToUserName", ToUserName);
uploadmediarequest.put("FileMd5", DigestUtils.md5(data));
HttpEntity paramEntity = MultipartEntityBuilder.create()
.setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
.addTextBody("id", StringUtil.getUuid(), ContentType.TEXT_PLAIN)
.addTextBody("name", fileName, ContentType.TEXT_PLAIN)
.addTextBody("type", contentType.getMimeType(), ContentType.TEXT_PLAIN)
.addTextBody("lastModifieDate", millis + "", ContentType.TEXT_PLAIN)
.addTextBody("size", data.length + "", ContentType.TEXT_PLAIN)
.addTextBody("mediatype", WechatUtil.getMediatype(contentType.getMimeType()), ContentType.TEXT_PLAIN)
.addTextBody("uploadmediarequest", uploadmediarequest.toJSONString(), ContentType.TEXT_PLAIN)
.addTextBody("webwx_data_ticket", dataTicket, ContentType.TEXT_PLAIN)
.addTextBody("pass_ticket", passticket, ContentType.TEXT_PLAIN)
.addBinaryBody("filename", data, contentType, fileName)
.build();
httpPost.setEntity(paramEntity);
HttpResponse response = httpClient.execute(httpPost);
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);
JSONObject result = JSONObject.parseObject(res);
return result;
} catch (Exception e) {
logger.error("上传媒体文件异常", e);
return null;
}
}
}

View File

@ -0,0 +1,59 @@
package com.hotlcc.wechat4j.model;
import com.hotlcc.wechat4j.util.WechatUtil;
/**
* 基本请求模型
*/
public class BaseRequest {
public BaseRequest() {
}
public BaseRequest(String DeviceID, String Sid, String Skey, String Uin) {
this.DeviceID = DeviceID;
this.Sid = Sid;
this.Skey = Skey;
this.Uin = Uin;
}
public BaseRequest(String Sid, String Skey, String Uin) {
this(WechatUtil.createDeviceID(), Sid, Skey, Uin);
}
private String DeviceID;
private String Sid;
private String Skey;
private String Uin;
public String getDeviceID() {
return DeviceID;
}
public void setDeviceID(String deviceID) {
DeviceID = deviceID;
}
public String getSid() {
return Sid;
}
public void setSid(String sid) {
Sid = sid;
}
public String getSkey() {
return Skey;
}
public void setSkey(String skey) {
Skey = skey;
}
public String getUin() {
return Uin;
}
public void setUin(String uin) {
Uin = uin;
}
}

View File

@ -0,0 +1,61 @@
package com.hotlcc.wechat4j.model;
/**
* 要发送的消息
*/
public class WxMessage {
private String ClientMsgId;
private String Content;
private String FromUserName;
private String LocalID;
private String ToUserName;
private Integer type;
public String getClientMsgId() {
return ClientMsgId;
}
public void setClientMsgId(String clientMsgId) {
ClientMsgId = clientMsgId;
}
public String getContent() {
return Content;
}
public void setContent(String content) {
Content = content;
}
public String getFromUserName() {
return FromUserName;
}
public void setFromUserName(String fromUserName) {
FromUserName = fromUserName;
}
public String getLocalID() {
return LocalID;
}
public void setLocalID(String localID) {
LocalID = localID;
}
public String getToUserName() {
return ToUserName;
}
public void setToUserName(String toUserName) {
ToUserName = toUserName;
}
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
}

View File

@ -3,6 +3,7 @@ package com.hotlcc.wechat4j.util;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.UUID;
public final class StringUtil {
private StringUtil() {
@ -31,4 +32,8 @@ public final class StringUtil {
throw new RuntimeException(e);
}
}
public static String getUuid() {
return UUID.randomUUID().toString().replace("-", "").toLowerCase();
}
}

View File

@ -29,29 +29,6 @@ public final class WechatUtil {
return System.currentTimeMillis() + RandomStringUtils.random(4, STRING_CHARS_2);
}
/**
* 创建BaseRequest
*
* @return
*/
public static JSONObject createBaseRequest(String DeviceID, String wxsid, String skey, String wxuin) {
JSONObject BaseRequest = new JSONObject();
BaseRequest.put("DeviceID", DeviceID);
BaseRequest.put("Sid", wxsid);
BaseRequest.put("Skey", skey);
BaseRequest.put("Uin", wxuin);
return BaseRequest;
}
/**
* 创建BaseRequest
*
* @return
*/
public static JSONObject createBaseRequest(String wxsid, String skey, String wxuin) {
return createBaseRequest(createDeviceID(), wxsid, skey, wxuin);
}
/**
* 把SyncKeyList转为字符串格式
*
@ -76,19 +53,19 @@ public final class WechatUtil {
}
/**
* 创建要发送的Msg
* 根据ContentType得到微信上传所需的mediatype
*
* @param contentType
* @return
*/
public static JSONObject createSendMsg(String Content, int Type, String FromUserName, String ToUserName) {
JSONObject Msg = new JSONObject();
String msgId = WechatUtil.createMsgId();
Msg.put("ClientMsgId", msgId);
Msg.put("Content", Content);
Msg.put("FromUserName", FromUserName);
Msg.put("LocalID", msgId);
Msg.put("ToUserName", ToUserName);
Msg.put("Type", Type);
return Msg;
public static String getMediatype(String contentType) {
if (contentType == null) {
return "doc";
}
if (contentType.indexOf("image") >= 0) {
return "pic";
} else {
return "doc";
}
}
}

View File

@ -28,3 +28,5 @@ webwx-url.batchgetcontact_url=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxbatchg
webwx-url.webwxsync_url=https://wx2.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>
## 4.3、上传媒体文件
webwx-url.uploadmedia_url=https://file.wx2.qq.com/cgi-bin/mmwebwx-bin/webwxuploadmedia?f=json