mirror of
https://gitee.com/hotlcc/wechat4j.git
synced 2026-01-15 15:21:56 +08:00
Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
56791e7965 | ||
|
|
fcd0316320 | ||
|
|
3749cdbc21 | ||
|
|
7de2bae4cc | ||
|
|
166db64b01 | ||
|
|
81ab8dd81c | ||
|
|
433e342ea0 | ||
|
|
c8f21dbdc9 | ||
|
|
4facae51c9 | ||
|
|
952040f6a6 | ||
|
|
a8a2b453ec | ||
|
|
11f3b99524 | ||
|
|
9302b2e68c | ||
|
|
53e7fedc6c | ||
|
|
31f84b62bf | ||
|
|
c9b7c7c4bb | ||
|
|
a98b21b23c | ||
|
|
9f36722bc4 | ||
|
|
533f936ac0 | ||
|
|
f0b1690023 | ||
|
|
743d40c847 | ||
|
|
5c9aee686e | ||
|
|
0d8b3c78e7 | ||
|
|
cf228920ee | ||
|
|
4eebb0ab10 | ||
|
|
ce21807e3b | ||
|
|
cba6b34a16 | ||
|
|
1c57501c76 | ||
|
|
ed6a842b8f | ||
|
|
8120000809 | ||
|
|
97e67e28e1 | ||
|
|
80538def1a | ||
|
|
c6d1ca83f3 | ||
|
|
ab094dad76 | ||
|
|
59a95df99a | ||
|
|
5995be80ba | ||
|
|
0c6356a71a | ||
|
|
76a2fa0dc1 |
56
README.md
56
README.md
@@ -6,11 +6,9 @@
|
||||
|
||||
码云主页:[https://gitee.com/hotlcc](https://gitee.com/hotlcc)
|
||||
|
||||
[](https://gitee.com/hotlcc)
|
||||
[](https://github.com/hotlcc)
|
||||
[](https://www.toutiao.com/c/user/3341863552/#mid=51655113888)
|
||||
[](https://weibo.com/hotloveu?is_hot=1)
|
||||
[](http://www.apache.org/licenses/LICENSE-2.0.html)
|
||||
[](https://raw.githubusercontent.com/996icu/996.ICU/master/LICENSE_CN)
|
||||
<a href="https://996.icu"><img src="https://img.shields.io/badge/link-996.icu-red.svg"></a>
|
||||
|
||||
## Web微信API文档
|
||||
|
||||
@@ -19,10 +17,8 @@
|
||||
## 简单使用
|
||||
|
||||
```java
|
||||
WebWeixinApi api = new WebWeixinApi();
|
||||
// 实例化微信客户端
|
||||
Wechat wechat = new Wechat();
|
||||
wechat.setWebWeixinApi(api);
|
||||
// 自动登录
|
||||
wechat.autoLogin();
|
||||
```
|
||||
@@ -33,14 +29,50 @@ wechat.autoLogin();
|
||||
|
||||
```java
|
||||
// 通过userName发送文本消息
|
||||
public JSONObject sendText(String content, String userName);
|
||||
// 通过昵称发送消息
|
||||
public JSONObject sendTextToNickName(String content, String nickName);
|
||||
// 通过备注名发送消息
|
||||
public JSONObject sendTextToRemarkName(String content, String remarkName);
|
||||
JSONObject sendTextToUserName(String content, String userName);
|
||||
// 通过昵称发送文本消息
|
||||
JSONObject sendTextToNickName(String content, String nickName);
|
||||
// 通过备注名发送文本消息
|
||||
JSONObject sendTextToRemarkName(String content, String remarkName);
|
||||
// 发送文本消息(根据多种名称)
|
||||
JSONObject sendText(String userName, String nickName, String remarkName, String content);
|
||||
```
|
||||
|
||||
> 目前仅支持发送文本消息,更多消息类型支持尽请期待。
|
||||
### 图片消息
|
||||
|
||||
```java
|
||||
// 通过userName发送图片消息
|
||||
JSONObject sendImageToUserName(String userName, byte[] mediaData, String mediaName, ContentType contentType);
|
||||
JSONObject sendImageToUserName(String userName, File image);
|
||||
// 通过昵称发送图片消息
|
||||
JSONObject sendImageToNickName(String nickName, byte[] mediaData, String mediaName, ContentType contentType);
|
||||
JSONObject sendImageToNickName(String nickName, File image);
|
||||
// 通过备注名发送图片消息
|
||||
JSONObject sendImageToRemarkName(String remarkName, byte[] mediaData, String mediaName, ContentType contentType);
|
||||
JSONObject sendImageToRemarkName(String remarkName, File image);
|
||||
// 发送图片消息(根据多种名称)
|
||||
JSONObject sendImage(String userName, String nickName, String remarkName, byte[] mediaData, String mediaName, ContentType contentType);
|
||||
JSONObject sendImage(String userName, String nickName, String remarkName, File image);
|
||||
```
|
||||
|
||||
### 视频消息
|
||||
|
||||
```java
|
||||
// 通过userName发送视频消息
|
||||
JSONObject sendVideoToUserName(String userName, byte[] mediaData, String mediaName, ContentType contentType);
|
||||
JSONObject sendVideoToUserName(String userName, File video);
|
||||
// 通过昵称发送视频消息
|
||||
JSONObject sendVideoToNickName(String nickName, byte[] mediaData, String mediaName, ContentType contentType);
|
||||
JSONObject sendVideoToNickName(String nickName, File video);
|
||||
// 通过备注名发送视频消息
|
||||
JSONObject sendVideoToRemarkName(String remarkName, byte[] mediaData, String mediaName, ContentType contentType);
|
||||
JSONObject sendVideoToRemarkName(String remarkName, File video);
|
||||
// 发送视频消息(根据多种名称)
|
||||
JSONObject sendVideo(String userName, String nickName, String remarkName, byte[] mediaData, String mediaName, ContentType contentType);
|
||||
JSONObject sendVideo(String userName, String nickName, String remarkName, File video);
|
||||
```
|
||||
|
||||
> 更多消息类型支持尽请期待。
|
||||
|
||||
## 消息处理器
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ URL参数分析:
|
||||
|
||||
FORM表单参数分析:
|
||||
|
||||
|数名|示例值|描述|
|
||||
|参数名|示例值|描述|
|
||||
|---|---|---|
|
||||
|sid||登录时获取的;|
|
||||
|uin||登录时获取的;|
|
||||
@@ -924,7 +924,7 @@ POST参数分析:
|
||||
- 10002:撤回消息
|
||||
- SyncKey会暂存起来作为下一次请求的参数。
|
||||
|
||||
### 4.2、发送消息
|
||||
### 4.2、发送文本消息
|
||||
|
||||
打开一个聊天界面,向好友发送一条消息,会发现产生如下 POST 请求:
|
||||
|
||||
@@ -996,3 +996,128 @@ POST参数分析:
|
||||
```
|
||||
https://file.wx.qq.com/cgi-bin/mmwebwx-bin/webwxuploadmedia?f=json
|
||||
```
|
||||
|
||||
若文件较小,则只会产生一个该请求,若文件较大,则会产生多个该请求。多个请求表示以分片的方式发送文件数据,分片大小约为524288。
|
||||
|
||||
FORM表单参数分析:
|
||||
|
||||
|参数名|示例值|描述|
|
||||
|---|---|---|
|
||||
|~~id~~|WU_FILE_0|页面文件组件ID;非必须;|
|
||||
|~~name~~|bd00c8eed5c2cd522e69f38317b46903.jpg|文件名;非必须;|
|
||||
|~~type~~|image/jpeg|文件的MimeType;非必须;|
|
||||
|~~lastModifieDate~~||文件最后修改时间;非必须;|
|
||||
|~~size~~|99785|文件大小;非必须;|
|
||||
|chunks|3|文件分片数量;文件较大需要分片时必须;|
|
||||
|chunk|0|文件分片序号;从0开始;文件较大需要分片时必须;|
|
||||
|mediatype|pic|文件类型;图片为pic,视频为video,其它文件为doc;必须;|
|
||||
|uploadmediarequest||JSON字符串;必须;|
|
||||
|webwx_data_ticket||cookie中的数据;必须;|
|
||||
|pass_ticket||登录时获取的;必须;|
|
||||
|filename||文件二进制数据;必须;|
|
||||
|
||||
uploadmediarequest结构示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"UploadType": 2,
|
||||
"BaseRequest": {
|
||||
"Uin": 1245,
|
||||
"Sid": "zxaODbK4ed",
|
||||
"Skey": "@crypt_4f399da_3c7a87e93b7872bce",
|
||||
"DeviceID": "e69688819413"
|
||||
},
|
||||
"ClientMediaId": 153686311,
|
||||
"TotalLen": 87508,
|
||||
"StartPos": 0,
|
||||
"DataLen": 87508,
|
||||
"MediaType": 4,
|
||||
"FromUserName": "@6feb88ee01067121479f686",
|
||||
"ToUserName": "@6feb88ee0106f67121479f686",
|
||||
"FileMd5": "717d1dbb9833c7cdbdd09ac"
|
||||
}
|
||||
```
|
||||
|
||||
服务端返回数据:
|
||||
|
||||
```json
|
||||
{
|
||||
"BaseResponse": {
|
||||
"Ret": 0,
|
||||
"ErrMsg": ""
|
||||
},
|
||||
"MediaId": "@crypt_17ab5.................39bd9cfa9ab",
|
||||
"StartPos": 99785,
|
||||
"CDNThumbImgHeight": 56,
|
||||
"CDNThumbImgWidth": 100,
|
||||
"EncryFileName": "bd00c8e.....38317b46903.jpg"
|
||||
}
|
||||
```
|
||||
|
||||
上传成功后,返回数据中会有MediaId,如果是分片上传的,则最后一个请求会返回MediaId。
|
||||
|
||||
### 4.4、发送图片消息
|
||||
|
||||
发送图片后,紧接着4.3的是如下POST请求:
|
||||
|
||||
```
|
||||
https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsgimg?fun=async&f=json&lang=zh_CN&pass_ticket=xFAjPcq0eXh.......TYHHdHgVL52eHo%253D
|
||||
```
|
||||
|
||||
URL参数分析:
|
||||
|
||||
|数名|示例值|描述|
|
||||
|---|---|---|
|
||||
|pass_ticket|xFAjPcq0eXh.......TYHHdHgVL52eHo%253D|同前面获取的;|
|
||||
|
||||
POST的数据(JSON):
|
||||
|
||||
```json
|
||||
{
|
||||
"BaseRequest": {
|
||||
"Uin": 16...245,
|
||||
"Sid": "KvCP..../TNqh8",
|
||||
"Skey": "@crypt_4fb399da......9f1b3d997c4b5eef82",
|
||||
"DeviceID": "e2825...3652448"
|
||||
},
|
||||
"Msg": {
|
||||
"Type": 3,
|
||||
"MediaId": "@crypt_17ab5.................39bd9cfa9ab",
|
||||
"Content": "",
|
||||
"FromUserName": "@3641f45.......69bed57642",
|
||||
"ToUserName": "@3641f454....9bed57642",
|
||||
"LocalID": "153691....0527",
|
||||
"ClientMsgId": "1536....390527"
|
||||
},
|
||||
"Scene": 0
|
||||
}
|
||||
```
|
||||
|
||||
POST参数分析:
|
||||
|
||||
|Key|示例值|描述|
|
||||
|---|---|---|
|
||||
|BaseRequest||同上;|
|
||||
|Msg.ClientMsgId||同LocalID;|
|
||||
|Msg.Content||消息内容;消息为媒体时,该值为媒体ID。|
|
||||
|Msg.FromUserName||发送用户;|
|
||||
|Msg.LocalID||13位时间戳+4位随机数;|
|
||||
|Msg.ToUserName||接收用户;|
|
||||
|Msg.Type|3|消息类型;同3.1中接收的消息类型;|
|
||||
|Msg.MediaId||4.3接口中返回的MediaId;|
|
||||
|Scene|0|固定值;|
|
||||
|
||||
服务端返回数据:
|
||||
|
||||
```json
|
||||
{
|
||||
"BaseResponse": {
|
||||
"Ret": 0,
|
||||
"ErrMsg": ""
|
||||
},
|
||||
"MsgID": "28832......8291836",
|
||||
"LocalID": "1536.....54390527"
|
||||
}
|
||||
```
|
||||
|
||||
Web微信发送图片,需要先调4.3的接口将媒体文件上传到服务器,然后再调4.4的接口发送图片的相关信息。
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>com.hotlcc</groupId>
|
||||
<artifactId>wechat4j</artifactId>
|
||||
<version>0.1.1</version>
|
||||
<version>0.2.5</version>
|
||||
|
||||
<name>wechat4j</name>
|
||||
<description>Wechat client for Java.</description>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
17
src/main/java/com/hotlcc/wechat4j/enums/ExitType.java
Normal file
17
src/main/java/com/hotlcc/wechat4j/enums/ExitType.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.hotlcc.wechat4j.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
/**
|
||||
* 微信退出类型
|
||||
*
|
||||
* @author Allen
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public enum ExitType {
|
||||
ERROR_EXIT("错误退出"),
|
||||
LOCAL_EXIT("本地退出"),
|
||||
REMOTE_EXIT("远程退出");
|
||||
|
||||
private String desc;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package com.hotlcc.wechat4j.enums;
|
||||
|
||||
/**
|
||||
* 微信退出类型
|
||||
*/
|
||||
public enum ExitTypeEnum {
|
||||
ERROR_EXIT("错误导致退出"),
|
||||
LOCAL_EXIT("本次手动退出"),
|
||||
REMOTE_EXIT("远程操作退出");
|
||||
|
||||
private String desc;
|
||||
|
||||
ExitTypeEnum(String desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,26 +1,23 @@
|
||||
package com.hotlcc.wechat4j.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 等待确认登录的tip
|
||||
*
|
||||
* @author https://gitee.com/hotlcc
|
||||
* @author Allen
|
||||
*/
|
||||
public enum LoginTipEnum {
|
||||
@SuppressWarnings("unused")
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum LoginTip {
|
||||
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 + "";
|
||||
22
src/main/java/com/hotlcc/wechat4j/enums/MediaType.java
Normal file
22
src/main/java/com/hotlcc/wechat4j/enums/MediaType.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package com.hotlcc.wechat4j.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author Allen
|
||||
* @version 1.0
|
||||
* @date 2019/4/17 9:51
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum MediaType {
|
||||
PICTURE(4, "pic"),
|
||||
VIDEO(4, "video");
|
||||
|
||||
public static String REQUEST_KEY = "mediatype";
|
||||
public static String REQUEST_JSON_KEY = "MediaType";
|
||||
|
||||
private Integer code;
|
||||
private String value;
|
||||
}
|
||||
@@ -1,11 +1,17 @@
|
||||
package com.hotlcc.wechat4j.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 消息类型enum
|
||||
*
|
||||
* @author https://gitee.com/hotlcc
|
||||
* @author Allen
|
||||
*/
|
||||
public enum MsgTypeEnum {
|
||||
@SuppressWarnings({"unused"})
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum MsgType {
|
||||
TEXT_MSG(1, "文本消息"),
|
||||
IMAGE_MSG(3, "图片消息"),
|
||||
VOICE_MSG(34, "语音消息"),
|
||||
@@ -25,19 +31,6 @@ public enum MsgTypeEnum {
|
||||
SYSTEM_MSG(10000, "系统消息"),
|
||||
WITHDRAW_MSG(10002, "撤回消息");
|
||||
|
||||
MsgTypeEnum(int code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
private int code;
|
||||
private String desc;
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
35
src/main/java/com/hotlcc/wechat4j/enums/OperatingSystem.java
Normal file
35
src/main/java/com/hotlcc/wechat4j/enums/OperatingSystem.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package com.hotlcc.wechat4j.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 操作系统enum
|
||||
*
|
||||
* @author Allen
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum OperatingSystem {
|
||||
DARWIN("darwin"),
|
||||
WINDOWS("windows"),
|
||||
LINUX("linux"),
|
||||
MAC_OS("mac"),
|
||||
OTHER("other");
|
||||
|
||||
private String value;
|
||||
|
||||
public static OperatingSystem currentOperatingSystem() {
|
||||
String osName = System.getProperty("os.name").toLowerCase();
|
||||
if (osName.contains(OperatingSystem.DARWIN.getValue())) {
|
||||
return OperatingSystem.DARWIN;
|
||||
} else if (osName.contains(OperatingSystem.WINDOWS.getValue())) {
|
||||
return OperatingSystem.WINDOWS;
|
||||
} else if (osName.contains(OperatingSystem.LINUX.getValue())) {
|
||||
return OperatingSystem.LINUX;
|
||||
} else if (osName.contains(OperatingSystem.MAC_OS.getValue())) {
|
||||
return OperatingSystem.MAC_OS;
|
||||
}
|
||||
return OperatingSystem.OTHER;
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,16 @@
|
||||
package com.hotlcc.wechat4j.enums;
|
||||
|
||||
public enum RetcodeEnum {
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Ret代码
|
||||
*
|
||||
* @author Allen
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum Retcode {
|
||||
RECODE_0(0, "正常"),
|
||||
RECODE_1100(1100, "失败/登出微信"),
|
||||
RECODE_1101(1101, "从其它设备登录微信");
|
||||
@@ -8,18 +18,9 @@ public enum RetcodeEnum {
|
||||
private int code;
|
||||
private String desc;
|
||||
|
||||
RetcodeEnum(int code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public static RetcodeEnum valueOf(int code) {
|
||||
RetcodeEnum[] es = values();
|
||||
for (RetcodeEnum e : es) {
|
||||
public static Retcode valueOf(int code) {
|
||||
Retcode[] es = values();
|
||||
for (Retcode e : es) {
|
||||
if (e.code == code) {
|
||||
return e;
|
||||
}
|
||||
@@ -1,6 +1,14 @@
|
||||
package com.hotlcc.wechat4j.enums;
|
||||
|
||||
public enum SelectorEnum {
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
/**
|
||||
* Selector代码
|
||||
*
|
||||
* @author Allen
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public enum Selector {
|
||||
SELECTOR_0(0, "正常"),
|
||||
SELECTOR_2(2, "有新消息"),
|
||||
SELECTOR_4(4, "目前发现修改了联系人备注会出现"),
|
||||
@@ -10,18 +18,9 @@ public enum SelectorEnum {
|
||||
private int code;
|
||||
private String desc;
|
||||
|
||||
SelectorEnum(int code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public static SelectorEnum valueOf(int code) {
|
||||
SelectorEnum[] es = values();
|
||||
for (SelectorEnum e : es) {
|
||||
public static Selector valueOf(int code) {
|
||||
Selector[] es = values();
|
||||
for (Selector e : es) {
|
||||
if (e.code == code) {
|
||||
return e;
|
||||
}
|
||||
@@ -1,39 +1,41 @@
|
||||
package com.hotlcc.wechat4j.handler;
|
||||
|
||||
import com.hotlcc.wechat4j.Wechat;
|
||||
import com.hotlcc.wechat4j.enums.ExitTypeEnum;
|
||||
import com.hotlcc.wechat4j.enums.ExitType;
|
||||
|
||||
/**
|
||||
* 退出事件处理器
|
||||
*
|
||||
* @author Allen
|
||||
*/
|
||||
public interface ExitEventHandler {
|
||||
/**
|
||||
* 针对所有类型的退出事件
|
||||
*
|
||||
* @param wechat
|
||||
* @param type
|
||||
* @param t
|
||||
* @param wechat 微信客户端
|
||||
* @param type 退出类型
|
||||
* @param t 异常
|
||||
*/
|
||||
void handleAllType(Wechat wechat, ExitTypeEnum type, Throwable t);
|
||||
void handleAllType(Wechat wechat, ExitType type, Throwable t);
|
||||
|
||||
/**
|
||||
* 针对错误导致的退出事件
|
||||
*
|
||||
* @param wechat
|
||||
* @param wechat 微信客户端
|
||||
*/
|
||||
void handleErrorExitEvent(Wechat wechat);
|
||||
|
||||
/**
|
||||
* 针对远程人为导致的退出事件
|
||||
*
|
||||
* @param wechat
|
||||
* @param wechat 微信客户端
|
||||
*/
|
||||
void handleRemoteExitEvent(Wechat wechat);
|
||||
|
||||
/**
|
||||
* 针对本地任务导致的退出事件
|
||||
*
|
||||
* @param wechat
|
||||
* @param wechat 微信客户端
|
||||
*/
|
||||
void handleLocalExitEvent(Wechat wechat);
|
||||
}
|
||||
|
||||
@@ -4,14 +4,16 @@ import com.hotlcc.wechat4j.Wechat;
|
||||
import com.hotlcc.wechat4j.model.ReceivedMsg;
|
||||
|
||||
/**
|
||||
* 接收消息处理器
|
||||
* 接收消息的消息处理器
|
||||
*
|
||||
* @author Allen
|
||||
*/
|
||||
public interface ReceivedMsgHandler {
|
||||
/**
|
||||
* 处理所有类型的消息
|
||||
*
|
||||
* @param wechat
|
||||
* @param msg
|
||||
* @param wechat 微信客户端
|
||||
* @param msg 接收的消息
|
||||
*/
|
||||
void handleAllType(Wechat wechat, ReceivedMsg msg);
|
||||
}
|
||||
|
||||
@@ -1,15 +1,26 @@
|
||||
package com.hotlcc.wechat4j.model;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AppInfo
|
||||
*
|
||||
* @author Allen
|
||||
*/
|
||||
@Getter
|
||||
public final class AppInfo {
|
||||
@Setter
|
||||
public final class AppInfo implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private AppInfo() {
|
||||
}
|
||||
|
||||
@@ -22,10 +33,7 @@ public final class AppInfo {
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
AppInfo appInfo = new AppInfo();
|
||||
appInfo.type = info.getInteger("Type");
|
||||
appInfo.appID = info.getString("AppID");
|
||||
return appInfo;
|
||||
return JSON.toJavaObject(info, AppInfo.class);
|
||||
}
|
||||
|
||||
public static List<AppInfo> valueOf(JSONArray infos) {
|
||||
|
||||
@@ -5,12 +5,18 @@ import com.hotlcc.wechat4j.util.WechatUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 基本请求模型
|
||||
*
|
||||
* @author Allen
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class BaseRequest {
|
||||
public class BaseRequest implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public BaseRequest() {
|
||||
}
|
||||
|
||||
|
||||
17
src/main/java/com/hotlcc/wechat4j/model/MediaMessage.java
Normal file
17
src/main/java/com/hotlcc/wechat4j/model/MediaMessage.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.hotlcc.wechat4j.model;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 媒体消息
|
||||
*
|
||||
* @author Allen
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class MediaMessage extends WxMessage {
|
||||
@JSONField(name = "MediaId")
|
||||
private String mediaId;
|
||||
}
|
||||
@@ -1,15 +1,21 @@
|
||||
package com.hotlcc.wechat4j.model;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
public final class ReceivedMsg {
|
||||
@Setter
|
||||
public final class ReceivedMsg implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private ReceivedMsg() {
|
||||
}
|
||||
|
||||
@@ -75,37 +81,7 @@ public final class ReceivedMsg {
|
||||
return null;
|
||||
}
|
||||
|
||||
ReceivedMsg receivedMsg = new ReceivedMsg();
|
||||
|
||||
receivedMsg.subMsgType = msg.getInteger("SubMsgType");
|
||||
receivedMsg.voiceLength = msg.getLong("VoiceLength");
|
||||
receivedMsg.fileName = msg.getString("FileName");
|
||||
receivedMsg.imgHeight = msg.getLong("ImgHeight");
|
||||
receivedMsg.toUserName = msg.getString("ToUserName");
|
||||
receivedMsg.hasProductId = msg.getLong("HasProductId");
|
||||
receivedMsg.imgStatus = msg.getInteger("ImgStatus");
|
||||
receivedMsg.url = msg.getString("Url");
|
||||
receivedMsg.imgWidth = msg.getInteger("ImgWidth");
|
||||
receivedMsg.forwardFlag = msg.getInteger("ForwardFlag");
|
||||
receivedMsg.status = msg.getInteger("Status");
|
||||
receivedMsg.ticket = msg.getString("Ticket");
|
||||
receivedMsg.recommendInfo = com.hotlcc.wechat4j.model.RecommendInfo.valueOf(msg.getJSONObject("RecommendInfo"));
|
||||
receivedMsg.createTime = msg.getLong("CreateTime");
|
||||
receivedMsg.newMsgId = msg.getLong("NewMsgId");
|
||||
receivedMsg.msgType = msg.getInteger("MsgType");
|
||||
receivedMsg.encryFileName = msg.getString("EncryFileName");
|
||||
receivedMsg.msgId = msg.getString("MsgId");
|
||||
receivedMsg.statusNotifyCode = msg.getInteger("StatusNotifyCode");
|
||||
receivedMsg.appInfo = com.hotlcc.wechat4j.model.AppInfo.valueOf(msg.getJSONObject("AppInfo"));
|
||||
receivedMsg.playLength = msg.getLong("PlayLength");
|
||||
receivedMsg.mediaId = msg.getString("MediaId");
|
||||
receivedMsg.content = msg.getString("Content");
|
||||
receivedMsg.statusNotifyUserName = msg.getString("StatusNotifyUserName");
|
||||
receivedMsg.fromUserName = msg.getString("FromUserName");
|
||||
receivedMsg.oriContent = msg.getString("OriContent");
|
||||
receivedMsg.fileSize = msg.getString("FileSize");
|
||||
|
||||
return receivedMsg;
|
||||
return JSON.toJavaObject(msg, ReceivedMsg.class);
|
||||
}
|
||||
|
||||
public static List<ReceivedMsg> valueOf(JSONArray msgs) {
|
||||
|
||||
@@ -1,15 +1,26 @@
|
||||
package com.hotlcc.wechat4j.model;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* RecommendInfo
|
||||
*
|
||||
* @author Allen
|
||||
*/
|
||||
@Getter
|
||||
public final class RecommendInfo {
|
||||
@Setter
|
||||
public final class RecommendInfo implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private RecommendInfo() {
|
||||
}
|
||||
|
||||
@@ -47,24 +58,7 @@ public final class RecommendInfo {
|
||||
return null;
|
||||
}
|
||||
|
||||
RecommendInfo recommendInfo = new RecommendInfo();
|
||||
|
||||
recommendInfo.ticket = info.getString("Ticket");
|
||||
recommendInfo.userName = info.getString("UserName");
|
||||
recommendInfo.sex = info.getInteger("Sex");
|
||||
recommendInfo.attrStatus = info.getInteger("AttrStatus");
|
||||
recommendInfo.city = info.getString("City");
|
||||
recommendInfo.nickName = info.getString("NickName");
|
||||
recommendInfo.scene = info.getInteger("Scene");
|
||||
recommendInfo.province = info.getString("Province");
|
||||
recommendInfo.content = info.getString("Content");
|
||||
recommendInfo.alias = info.getString("Alias");
|
||||
recommendInfo.signature = info.getString("Signature");
|
||||
recommendInfo.opCode = info.getInteger("OpCode");
|
||||
recommendInfo.qqNum = info.getLong("QQNum");
|
||||
recommendInfo.verifyFlag = info.getInteger("VerifyFlag");
|
||||
|
||||
return recommendInfo;
|
||||
return JSON.toJavaObject(info, RecommendInfo.class);
|
||||
}
|
||||
|
||||
public static List<RecommendInfo> valueOf(JSONArray infos) {
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
package com.hotlcc.wechat4j.model;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 微信用户信息
|
||||
*
|
||||
* @author Allen
|
||||
*/
|
||||
@Getter
|
||||
public final class UserInfo {
|
||||
@Setter
|
||||
public final class UserInfo implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private UserInfo() {
|
||||
}
|
||||
|
||||
@@ -84,41 +92,7 @@ public final class UserInfo {
|
||||
return null;
|
||||
}
|
||||
|
||||
UserInfo userInfo = new UserInfo();
|
||||
|
||||
userInfo.uin = info.getLong("Uin");
|
||||
userInfo.nickName = info.getString("NickName");
|
||||
userInfo.headImgUrl = info.getString("HeadImgUrl");
|
||||
userInfo.contactFlag = info.getInteger("ContactFlag");
|
||||
userInfo.memberCount = info.getInteger("MemberCount");
|
||||
userInfo.memberList = valueOf(info.getJSONArray("MemberList"));
|
||||
userInfo.remarkName = info.getString("RemarkName");
|
||||
userInfo.hideInputBarFlag = info.getInteger("HideInputBarFlag");
|
||||
userInfo.sex = info.getInteger("Sex");
|
||||
userInfo.signature = info.getString("Signature");
|
||||
userInfo.verifyFlag = info.getInteger("VerifyFlag");
|
||||
userInfo.ownerUin = info.getLong("OwnerUin");
|
||||
userInfo.pyInitial = info.getString("PYInitial");
|
||||
userInfo.pyQuanPin = info.getString("PYQuanPin");
|
||||
userInfo.remarkPYInitial = info.getString("RemarkPYInitial");
|
||||
userInfo.remarkPYQuanPin = info.getString("RemarkPYQuanPin");
|
||||
userInfo.starFriend = info.getInteger("StarFriend");
|
||||
userInfo.appAccountFlag = info.getInteger("AppAccountFlag");
|
||||
userInfo.statues = info.getInteger("Statues");
|
||||
userInfo.attrStatus = info.getInteger("AttrStatus");
|
||||
userInfo.province = info.getString("Province");
|
||||
userInfo.city = info.getString("City");
|
||||
userInfo.alias = info.getString("Alias");
|
||||
userInfo.snsFlag = info.getInteger("SnsFlag");
|
||||
userInfo.uniFriend = info.getInteger("UniFriend");
|
||||
userInfo.displayName = info.getString("DisplayName");
|
||||
userInfo.chatRoomId = info.getLong("ChatRoomId");
|
||||
userInfo.keyWord = info.getString("KeyWord");
|
||||
userInfo.encryChatRoomId = info.getString("EncryChatRoomId");
|
||||
userInfo.isOwner = info.getInteger("IsOwner");
|
||||
userInfo.userName = info.getString("UserName");
|
||||
|
||||
return userInfo;
|
||||
return JSON.toJavaObject(info, UserInfo.class);
|
||||
}
|
||||
|
||||
public static List<UserInfo> valueOf(JSONArray infos) {
|
||||
|
||||
@@ -4,12 +4,18 @@ import com.alibaba.fastjson.annotation.JSONField;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 要发送的消息
|
||||
*
|
||||
* @author Allen
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class WxMessage {
|
||||
public class WxMessage implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@JSONField(name = "ClientMsgId")
|
||||
private String clientMsgId;
|
||||
@JSONField(name = "Content")
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
package com.hotlcc.wechat4j.util;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 通用工具类
|
||||
*
|
||||
* @author Allen
|
||||
*/
|
||||
@Slf4j
|
||||
public final class CommonUtil {
|
||||
private static Logger logger = LoggerFactory.getLogger(CommonUtil.class);
|
||||
|
||||
private CommonUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 睡眠线程
|
||||
*
|
||||
* @param millis 时间
|
||||
* @param nanos nanos
|
||||
*/
|
||||
public static void threadSleep(long millis, int nanos) {
|
||||
try {
|
||||
Thread.sleep(millis, nanos);
|
||||
@@ -17,6 +26,11 @@ public final class CommonUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 睡眠线程
|
||||
*
|
||||
* @param millis 时间
|
||||
*/
|
||||
public static void threadSleep(long millis) {
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
|
||||
82
src/main/java/com/hotlcc/wechat4j/util/FileUtil.java
Normal file
82
src/main/java/com/hotlcc/wechat4j/util/FileUtil.java
Normal file
@@ -0,0 +1,82 @@
|
||||
package com.hotlcc.wechat4j.util;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.http.entity.ContentType;
|
||||
|
||||
import javax.activation.MimetypesFileTypeMap;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 文件工具类
|
||||
*
|
||||
* @author Allen
|
||||
*/
|
||||
@Slf4j
|
||||
public final class FileUtil {
|
||||
private FileUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 从文件中获取二进制数据
|
||||
*
|
||||
* @param file 文件
|
||||
* @return 二进制数据
|
||||
*/
|
||||
public static byte[] getBytes(File file) {
|
||||
if (file == null) {
|
||||
throw new IllegalArgumentException("参数file不能为null");
|
||||
}
|
||||
|
||||
FileInputStream fis = null;
|
||||
ByteArrayOutputStream baos = null;
|
||||
try {
|
||||
fis = new FileInputStream(file);
|
||||
baos = new ByteArrayOutputStream();
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
|
||||
while ((len = fis.read(buffer)) != -1) {
|
||||
baos.write(buffer, 0, len);
|
||||
}
|
||||
|
||||
baos.flush();
|
||||
baos.close();
|
||||
fis.close();
|
||||
|
||||
return baos.toByteArray();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
if (fis != null) {
|
||||
try {
|
||||
fis.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (baos != null) {
|
||||
try {
|
||||
baos.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的ContentType
|
||||
*
|
||||
* @param file 文件
|
||||
* @return ContentType
|
||||
*/
|
||||
public static ContentType getContentType(File file) {
|
||||
String mimeType = new MimetypesFileTypeMap().getContentType(file);
|
||||
ContentType contentType = ContentType.parse(mimeType);
|
||||
return contentType;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,18 @@
|
||||
package com.hotlcc.wechat4j.util;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Properties工具类
|
||||
*
|
||||
* @author Allen
|
||||
*/
|
||||
@Slf4j
|
||||
public final class PropertiesUtil {
|
||||
private static Logger logger = LoggerFactory.getLogger(PropertiesUtil.class);
|
||||
|
||||
private PropertiesUtil() {
|
||||
}
|
||||
|
||||
@@ -33,7 +36,7 @@ public final class PropertiesUtil {
|
||||
is = PropertiesUtil.class.getClassLoader().getResourceAsStream(path);
|
||||
prop.load(is);
|
||||
} catch (Exception e) {
|
||||
logger.error("Loading properties file \"" + path + "\" error.", e);
|
||||
log.error("Loading properties file \"" + path + "\" error.", e);
|
||||
} finally {
|
||||
if (is != null) {
|
||||
try {
|
||||
|
||||
@@ -6,9 +6,8 @@ import com.google.zxing.NotFoundException;
|
||||
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.google.zxing.common.HybridBinarizer;
|
||||
import com.hotlcc.wechat4j.enums.OperatingSystemEnum;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import com.hotlcc.wechat4j.enums.OperatingSystem;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
@@ -16,25 +15,22 @@ import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 二维码工具类
|
||||
*
|
||||
* @author Allen
|
||||
*/
|
||||
@SuppressWarnings({"unused", "WeakerAccess"})
|
||||
@Slf4j
|
||||
public final class QRCodeUtil {
|
||||
private static Logger logger = LoggerFactory.getLogger(QRCodeUtil.class);
|
||||
|
||||
private QRCodeUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 从BitMatrix中得到boolean矩阵(不去除周围空白部分)
|
||||
*
|
||||
* @return
|
||||
* @return 得到的boolean矩阵
|
||||
*/
|
||||
private static boolean[][] toBoolMatrix(BitMatrix matrix) {
|
||||
return toBoolMatrix(matrix, false);
|
||||
@@ -43,9 +39,9 @@ public final class QRCodeUtil {
|
||||
/**
|
||||
* 从BitMatrix中得到boolean矩阵
|
||||
*
|
||||
* @param matrix
|
||||
* @param matrix BitMatrix
|
||||
* @param noMargin 是否去除周围空白
|
||||
* @return
|
||||
* @return 得到的boolean矩阵
|
||||
*/
|
||||
private static boolean[][] toBoolMatrix(BitMatrix matrix, boolean noMargin) {
|
||||
int width = matrix.getWidth();
|
||||
@@ -60,8 +56,8 @@ public final class QRCodeUtil {
|
||||
right = width - br[1] - 1;
|
||||
}
|
||||
boolean[][] m = new boolean[height - top - bottom][width - left - right];
|
||||
for (int h = 0 + top, i = 0; h < height - bottom; h++, i++) {
|
||||
for (int w = 0 + left, j = 0; w < width - right; w++, j++) {
|
||||
for (int h = top, i = 0; h < height - bottom; h++, i++) {
|
||||
for (int w = left, j = 0; w < width - right; w++, j++) {
|
||||
m[i][j] = matrix.get(w, h);
|
||||
}
|
||||
}
|
||||
@@ -71,8 +67,8 @@ public final class QRCodeUtil {
|
||||
/**
|
||||
* 将矩阵逆时针转90度
|
||||
*
|
||||
* @param matrix
|
||||
* @return
|
||||
* @param matrix 旋转前的矩阵
|
||||
* @return 旋转后的矩阵
|
||||
*/
|
||||
private static boolean[][] reverseMatrix(boolean[][] matrix) {
|
||||
if (matrix == null) {
|
||||
@@ -95,15 +91,14 @@ public final class QRCodeUtil {
|
||||
/**
|
||||
* 从boolMatrix左上角判断二维码定位标记的大小
|
||||
*
|
||||
* @param boolMatrix
|
||||
* @return
|
||||
* @param boolMatrix bool矩阵
|
||||
* @return 定位标记大小
|
||||
*/
|
||||
private static int getBitCharSize(boolean[][] boolMatrix) {
|
||||
int a = 0, b = 0;
|
||||
out:
|
||||
for (int i = 0, len = boolMatrix.length; i < len; i++) {
|
||||
for (boolean[] boolArr : boolMatrix) {
|
||||
boolean find = false;
|
||||
boolean[] boolArr = boolMatrix[i];
|
||||
for (int i2 = 0, len2 = boolArr.length; i2 < len2; i2++) {
|
||||
if (!find && boolArr[i2]) {
|
||||
find = true;
|
||||
@@ -122,59 +117,62 @@ public final class QRCodeUtil {
|
||||
/**
|
||||
* 从boolMatrix判断bit-char占位比
|
||||
*
|
||||
* @param boolMatrix
|
||||
* @return
|
||||
* @param boolMatrix bool矩阵
|
||||
* @return 占位比
|
||||
*/
|
||||
private static int getBitCharRatio(boolean[][] boolMatrix) {
|
||||
int[] size = new int[4];
|
||||
int len = 4;
|
||||
// 找出四个角的占位数
|
||||
int[] size = new int[len];
|
||||
size[0] = getBitCharSize(boolMatrix);
|
||||
for (int i = 1; i < 4; i++) {
|
||||
for (int i = 1; i < len; i++) {
|
||||
boolMatrix = reverseMatrix(boolMatrix);
|
||||
size[i] = getBitCharSize(boolMatrix);
|
||||
}
|
||||
|
||||
Map<Integer, Integer> map = new HashMap<>();
|
||||
for (int s : size) {
|
||||
Integer count = map.get(s);
|
||||
if (count == null) {
|
||||
map.put(s, 1);
|
||||
} else {
|
||||
map.put(s, count + 1);
|
||||
// 统计每个占位数出现的次数
|
||||
int[] num = new int[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
int n = 0;
|
||||
for (int s : size) {
|
||||
if (s == size[i]) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
num[i] = n;
|
||||
}
|
||||
Set<Map.Entry<Integer, Integer>> entrySet = map.entrySet();
|
||||
Integer k = null, v = null;
|
||||
int flag = 0;
|
||||
for (Map.Entry<Integer, Integer> entry : entrySet) {
|
||||
if (flag++ == 0) {
|
||||
k = entry.getKey();
|
||||
v = entry.getValue();
|
||||
continue;
|
||||
}
|
||||
if (entry.getValue() > v) {
|
||||
k = entry.getKey();
|
||||
v = entry.getValue();
|
||||
// 找出最多的次数
|
||||
int maxNum = num[0];
|
||||
for (int i = 1; i < len; i++) {
|
||||
maxNum = Math.max(maxNum, num[i]);
|
||||
}
|
||||
// 找出出现次数最多的占位数
|
||||
int s = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (num[i] == maxNum) {
|
||||
s = size[i];
|
||||
}
|
||||
}
|
||||
|
||||
return k.intValue() / 7;
|
||||
return s / 7;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将二维码图片转为字符矩阵
|
||||
*
|
||||
* @param image
|
||||
* @return
|
||||
* @param image 二维码图片
|
||||
* @param onStr 实体字符串
|
||||
* @param offStr 空白字符串
|
||||
* @return 字符矩阵
|
||||
*/
|
||||
public static String toCharMatrix(BufferedImage image, String onStr, String offStr) {
|
||||
LuminanceSource source = new BufferedImageLuminanceSource(image);
|
||||
Binarizer binarizer = new HybridBinarizer(source);
|
||||
BitMatrix matrix = null;
|
||||
BitMatrix matrix;
|
||||
try {
|
||||
matrix = binarizer.getBlackMatrix();
|
||||
boolean[][] boolMatrix = toBoolMatrix(matrix, true);
|
||||
int ratio = getBitCharRatio(boolMatrix);
|
||||
StringBuffer sb = new StringBuffer();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0, len = boolMatrix.length; i < len; i += ratio) {
|
||||
boolean[] boolArr = boolMatrix[i];
|
||||
for (int i2 = 0, len2 = boolArr.length; i2 < len2; i2 += ratio) {
|
||||
@@ -192,8 +190,8 @@ public final class QRCodeUtil {
|
||||
/**
|
||||
* 将二维码图片转为字符矩阵
|
||||
*
|
||||
* @param image
|
||||
* @return
|
||||
* @param image 二维码图片
|
||||
* @return 字符矩阵
|
||||
*/
|
||||
public static String toCharMatrix(BufferedImage image) {
|
||||
return toCharMatrix(image, " ", "██");
|
||||
@@ -202,8 +200,10 @@ public final class QRCodeUtil {
|
||||
/**
|
||||
* 将二维码图片转为字符矩阵
|
||||
*
|
||||
* @param data
|
||||
* @return
|
||||
* @param data 二维码图片的字节数据
|
||||
* @param onStr 实体字符串
|
||||
* @param offStr 空白字符串
|
||||
* @return 字符矩阵
|
||||
*/
|
||||
public static String toCharMatrix(byte[] data, String onStr, String offStr) {
|
||||
ByteArrayInputStream bais = null;
|
||||
@@ -228,8 +228,8 @@ public final class QRCodeUtil {
|
||||
/**
|
||||
* 将二维码图片转为字符矩阵
|
||||
*
|
||||
* @param data
|
||||
* @return
|
||||
* @param data 二维码图片的字节数据
|
||||
* @return 字符矩阵
|
||||
*/
|
||||
public static String toCharMatrix(byte[] data) {
|
||||
return toCharMatrix(data, " ", "██");
|
||||
@@ -238,8 +238,8 @@ public final class QRCodeUtil {
|
||||
/**
|
||||
* 将二维码图片数据写入到临时文件
|
||||
*
|
||||
* @param data
|
||||
* @return
|
||||
* @param data 二维码图片的字节数据
|
||||
* @return 字符矩阵
|
||||
*/
|
||||
public static File writeToTempFile(byte[] data) {
|
||||
FileOutputStream fos = null;
|
||||
@@ -250,7 +250,7 @@ public final class QRCodeUtil {
|
||||
fos.flush();
|
||||
return tmp;
|
||||
} catch (IOException e) {
|
||||
logger.error("二维码写入临时文件异常", e);
|
||||
log.error("二维码写入临时文件异常", e);
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
if (fos != null) {
|
||||
@@ -266,12 +266,12 @@ public final class QRCodeUtil {
|
||||
/**
|
||||
* 打开二维码图片
|
||||
*
|
||||
* @param data
|
||||
* @param data 二维码图片的字节数据
|
||||
*/
|
||||
public static void openQRCodeImage(byte[] data) {
|
||||
OperatingSystemEnum os = OperatingSystemEnum.currentOperatingSystem();
|
||||
Runtime runtime = null;
|
||||
File tmp = null;
|
||||
OperatingSystem os = OperatingSystem.currentOperatingSystem();
|
||||
Runtime runtime;
|
||||
File tmp;
|
||||
switch (os) {
|
||||
case WINDOWS:
|
||||
runtime = Runtime.getRuntime();
|
||||
|
||||
@@ -5,6 +5,11 @@ import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 字符串工具类
|
||||
*
|
||||
* @author Allen
|
||||
*/
|
||||
public final class StringUtil {
|
||||
private StringUtil() {
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package com.hotlcc.wechat4j.api;
|
||||
package com.hotlcc.wechat4j.util;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.hotlcc.wechat4j.enums.LoginTipEnum;
|
||||
import com.hotlcc.wechat4j.enums.LoginTip;
|
||||
import com.hotlcc.wechat4j.enums.MediaType;
|
||||
import com.hotlcc.wechat4j.model.BaseRequest;
|
||||
import com.hotlcc.wechat4j.model.MediaMessage;
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.http.*;
|
||||
import org.apache.http.client.HttpClient;
|
||||
@@ -22,14 +22,11 @@ import org.apache.http.entity.mime.MultipartEntityBuilder;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.json.XML;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.stringtemplate.v4.ST;
|
||||
|
||||
import javax.activation.MimetypesFileTypeMap;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -39,21 +36,33 @@ import java.util.regex.Pattern;
|
||||
*
|
||||
* @author Allen
|
||||
*/
|
||||
@SuppressWarnings("Duplicates")
|
||||
public class WebWeixinApi {
|
||||
private static Logger logger = LoggerFactory.getLogger(WebWeixinApi.class);
|
||||
@SuppressWarnings({"Duplicates", "unused"})
|
||||
@Slf4j
|
||||
public final class WebWeixinApiUtil {
|
||||
private WebWeixinApiUtil() {
|
||||
}
|
||||
|
||||
//预编译正则匹配
|
||||
/**
|
||||
* 预编译正则匹配
|
||||
*/
|
||||
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_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\\/");
|
||||
private static Pattern PATTERN_REDIRECT_URI_3 = Pattern.compile("http(s*)://wx(\\d*)\\.qq\\.com/");
|
||||
|
||||
/**
|
||||
* 上传媒体文件分片大小
|
||||
*/
|
||||
private static final int UPLOAD_MEDIA_FILE_CHUNK_SIZE = 524288;
|
||||
|
||||
/**
|
||||
* 获取微信uuid
|
||||
*
|
||||
* @param httpClient http客户端
|
||||
* @return 返回数据
|
||||
*/
|
||||
public JSONObject getWxUuid(HttpClient httpClient) {
|
||||
public static JSONObject getWxUuid(HttpClient httpClient) {
|
||||
try {
|
||||
String url = new ST(PropertiesUtil.getProperty("webwx-url.uuid_url"))
|
||||
.add("appid", PropertiesUtil.getProperty("webwx.appid"))
|
||||
@@ -98,7 +107,7 @@ public class WebWeixinApi {
|
||||
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
logger.error("获取uuid异常", e);
|
||||
log.error("获取uuid异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -106,10 +115,12 @@ public class WebWeixinApi {
|
||||
/**
|
||||
* 获取二维码
|
||||
*
|
||||
* @param uuid
|
||||
* @param httpClient http客户端
|
||||
* @param uuid uuid
|
||||
* @return 二维码图片字节数据
|
||||
*/
|
||||
public byte[] getQR(HttpClient httpClient,
|
||||
String uuid) {
|
||||
public static byte[] getQR(HttpClient httpClient,
|
||||
String uuid) {
|
||||
try {
|
||||
String url = new ST(PropertiesUtil.getProperty("webwx-url.qrcode_url"))
|
||||
.add("uuid", uuid)
|
||||
@@ -132,7 +143,7 @@ public class WebWeixinApi {
|
||||
|
||||
return data;
|
||||
} catch (Exception e) {
|
||||
logger.error("获取二维码异常", e);
|
||||
log.error("获取二维码异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -140,11 +151,14 @@ public class WebWeixinApi {
|
||||
/**
|
||||
* 获取跳转uri(等待扫码认证)
|
||||
*
|
||||
* @return
|
||||
* @param httpClient http客户端
|
||||
* @param tip 登录tip
|
||||
* @param uuid uuid
|
||||
* @return 返回数据
|
||||
*/
|
||||
public JSONObject getRedirectUri(HttpClient httpClient,
|
||||
LoginTipEnum tip,
|
||||
String uuid) {
|
||||
public static JSONObject getRedirectUri(HttpClient httpClient,
|
||||
LoginTip tip,
|
||||
String uuid) {
|
||||
try {
|
||||
long millis = System.currentTimeMillis();
|
||||
String url = new ST(PropertiesUtil.getProperty("webwx-url.redirect_uri"))
|
||||
@@ -201,7 +215,7 @@ public class WebWeixinApi {
|
||||
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
logger.error("获取跳转uri异常", e);
|
||||
log.error("获取跳转uri异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -209,9 +223,13 @@ public class WebWeixinApi {
|
||||
/**
|
||||
* 获取登录认证码
|
||||
* 此方法执行后,其它web端微信、pc端都会下线
|
||||
*
|
||||
* @param httpClient http客户端
|
||||
* @param redirectUri 调整uri
|
||||
* @return 返回数据
|
||||
*/
|
||||
public JSONObject getLoginCode(HttpClient httpClient,
|
||||
String redirectUri) {
|
||||
public static JSONObject getLoginCode(HttpClient httpClient,
|
||||
String redirectUri) {
|
||||
try {
|
||||
String url = new ST(PropertiesUtil.getProperty("webwx-url.newlogin_url"))
|
||||
.add("redirectUri", redirectUri)
|
||||
@@ -229,32 +247,34 @@ public class WebWeixinApi {
|
||||
HttpEntity entity = response.getEntity();
|
||||
String res = EntityUtils.toString(entity, Consts.UTF_8);
|
||||
|
||||
JSONObject result = JSONObject.parseObject(XML.toJSONObject(res).toString()).getJSONObject("error");
|
||||
|
||||
return result;
|
||||
return JSONObject.parseObject(XML.toJSONObject(res).toString()).getJSONObject("error");
|
||||
} catch (Exception e) {
|
||||
logger.error("获取登录认证码异常", e);
|
||||
log.error("获取登录认证码异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
*
|
||||
* @param httpClient http客户端
|
||||
* @param urlVersion url版本号
|
||||
* @param baseRequest BaseRequest
|
||||
*/
|
||||
public void logout(HttpClient httpClient,
|
||||
String urlVersion,
|
||||
BaseRequest BaseRequest) {
|
||||
public static void logout(HttpClient httpClient,
|
||||
String urlVersion,
|
||||
BaseRequest baseRequest) {
|
||||
try {
|
||||
List<NameValuePair> pairList = new ArrayList<>();
|
||||
pairList.add(new BasicNameValuePair("sid", BaseRequest.getSid()));
|
||||
pairList.add(new BasicNameValuePair("uin", BaseRequest.getUin()));
|
||||
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("urlVersion", urlVersion)
|
||||
.add("type", i)
|
||||
.add("skey", StringUtil.encodeURL(BaseRequest.getSkey(), Consts.UTF_8.name()))
|
||||
.add("skey", StringUtil.encodeURL(baseRequest.getSkey(), Consts.UTF_8.name()))
|
||||
.render();
|
||||
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
@@ -266,18 +286,22 @@ public class WebWeixinApi {
|
||||
httpClient.execute(httpPost);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("退出登录异常", e);
|
||||
log.error("退出登录异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* push登录
|
||||
*
|
||||
* @param httpClient http客户端
|
||||
* @param urlVersion url版本号
|
||||
* @param wxuin uin
|
||||
* @return 返回数据
|
||||
*/
|
||||
public JSONObject pushLogin(HttpClient httpClient,
|
||||
String urlVersion,
|
||||
String wxuin) {
|
||||
public static 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)
|
||||
@@ -297,22 +321,28 @@ public class WebWeixinApi {
|
||||
|
||||
return JSONObject.parseObject(res);
|
||||
} catch (Exception e) {
|
||||
logger.error("push登录异常", e);
|
||||
log.error("push登录异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取初始化数据
|
||||
*
|
||||
* @param httpClient http客户端
|
||||
* @param urlVersion url版本号
|
||||
* @param passticket passticket
|
||||
* @param baseRequest BaseRequest
|
||||
* @return 返回数据
|
||||
*/
|
||||
public JSONObject webWeixinInit(HttpClient httpClient,
|
||||
String urlVersion,
|
||||
String passticket,
|
||||
BaseRequest BaseRequest) {
|
||||
public static 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("pass_ticket", StringUtil.encodeURL(passticket, Consts.UTF_8.name()))
|
||||
.add("r", System.currentTimeMillis() / 1252L)
|
||||
.render();
|
||||
|
||||
@@ -320,7 +350,7 @@ public class WebWeixinApi {
|
||||
httpPost.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
|
||||
|
||||
JSONObject paramJson = new JSONObject();
|
||||
paramJson.put("BaseRequest", BaseRequest);
|
||||
paramJson.put("BaseRequest", baseRequest);
|
||||
HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8);
|
||||
httpPost.setEntity(paramEntity);
|
||||
|
||||
@@ -335,7 +365,7 @@ public class WebWeixinApi {
|
||||
|
||||
return JSONObject.parseObject(res);
|
||||
} catch (Exception e) {
|
||||
logger.error("获取初始化数据异常", e);
|
||||
log.error("获取初始化数据异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -343,24 +373,29 @@ public class WebWeixinApi {
|
||||
/**
|
||||
* 开启消息状态通知
|
||||
*
|
||||
* @return
|
||||
* @param httpClient http客户端
|
||||
* @param urlVersion url版本号
|
||||
* @param passticket passticket
|
||||
* @param baseRequest BaseRequest
|
||||
* @param loginUserName 当前登录账号用户名
|
||||
* @return 返回数据
|
||||
*/
|
||||
public JSONObject statusNotify(HttpClient httpClient,
|
||||
String urlVersion,
|
||||
String passticket,
|
||||
BaseRequest BaseRequest,
|
||||
String loginUserName) {
|
||||
public static 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)
|
||||
.add("pass_ticket", StringUtil.encodeURL(passticket, Consts.UTF_8.name()))
|
||||
.render();
|
||||
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
httpPost.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
|
||||
|
||||
JSONObject paramJson = new JSONObject();
|
||||
paramJson.put("BaseRequest", BaseRequest);
|
||||
paramJson.put("BaseRequest", baseRequest);
|
||||
paramJson.put("ClientMsgId", System.currentTimeMillis());
|
||||
paramJson.put("Code", 3);
|
||||
paramJson.put("FromUserName", loginUserName);
|
||||
@@ -379,28 +414,34 @@ public class WebWeixinApi {
|
||||
|
||||
return JSONObject.parseObject(res);
|
||||
} catch (Exception e) {
|
||||
logger.error("开启消息状态通知异常", e);
|
||||
log.error("开启消息状态通知异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务端状态同步心跳
|
||||
*
|
||||
* @param httpClient http客户端
|
||||
* @param urlVersion url版本号
|
||||
* @param baseRequest BaseRequest
|
||||
* @param syncKeyList SyncKeyList
|
||||
* @return 返回数据
|
||||
*/
|
||||
public JSONObject syncCheck(HttpClient httpClient,
|
||||
String urlVersion,
|
||||
BaseRequest BaseRequest,
|
||||
JSONArray SyncKeyList) {
|
||||
public static 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())
|
||||
.add("uin", BaseRequest.getUin())
|
||||
.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("synckey", StringUtil.encodeURL(WechatUtil.syncKeyListToString(syncKeyList), Consts.UTF_8.name()))
|
||||
.add("_", millis)
|
||||
.render();
|
||||
|
||||
@@ -432,18 +473,24 @@ public class WebWeixinApi {
|
||||
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
logger.error("服务端状态同步异常", e);
|
||||
log.error("服务端状态同步异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全部联系人列表
|
||||
*
|
||||
* @param httpClient http客户端
|
||||
* @param urlVersion url版本号
|
||||
* @param passticket passticket
|
||||
* @param skey skey
|
||||
* @return 返回数据
|
||||
*/
|
||||
public JSONObject getContact(HttpClient httpClient,
|
||||
String urlVersion,
|
||||
String passticket,
|
||||
String skey) {
|
||||
public static JSONObject getContact(HttpClient httpClient,
|
||||
String urlVersion,
|
||||
String passticket,
|
||||
String skey) {
|
||||
try {
|
||||
String url = new ST(PropertiesUtil.getProperty("webwx-url.getcontact_url"))
|
||||
.add("urlVersion", urlVersion)
|
||||
@@ -465,19 +512,26 @@ public class WebWeixinApi {
|
||||
|
||||
return JSONObject.parseObject(res);
|
||||
} catch (Exception e) {
|
||||
logger.error("获取全部联系人列表异常", e);
|
||||
log.error("获取全部联系人列表异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量获取指定用户信息
|
||||
*
|
||||
* @param httpClient http客户端
|
||||
* @param urlVersion url版本号
|
||||
* @param passticket passticket
|
||||
* @param baseRequest BaseRequest
|
||||
* @param batchContactList 联系人列表
|
||||
* @return 返回数据
|
||||
*/
|
||||
public JSONObject batchGetContact(HttpClient httpClient,
|
||||
String urlVersion,
|
||||
String passticket,
|
||||
BaseRequest BaseRequest,
|
||||
JSONArray batchContactList) {
|
||||
public static 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)
|
||||
@@ -489,7 +543,7 @@ public class WebWeixinApi {
|
||||
httpPost.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
|
||||
|
||||
JSONObject paramJson = new JSONObject();
|
||||
paramJson.put("BaseRequest", BaseRequest);
|
||||
paramJson.put("BaseRequest", baseRequest);
|
||||
paramJson.put("Count", batchContactList.size());
|
||||
paramJson.put("List", batchContactList);
|
||||
HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8);
|
||||
@@ -506,33 +560,76 @@ public class WebWeixinApi {
|
||||
|
||||
return JSONObject.parseObject(res);
|
||||
} catch (Exception e) {
|
||||
logger.error("批量获取指定联系人信息异常", e);
|
||||
log.error("批量获取指定联系人信息异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取联系人头像
|
||||
*
|
||||
* @param httpClient http客户端
|
||||
* @param urlVersion url版本号
|
||||
* @param username 用户名
|
||||
* @return 头像图片数据
|
||||
*/
|
||||
public static byte[] getContactHeadImg(HttpClient httpClient,
|
||||
String urlVersion,
|
||||
String username) {
|
||||
try {
|
||||
String url = new ST(PropertiesUtil.getProperty("webwx-url.webwxgetheadimg_url"))
|
||||
.add("urlVersion", urlVersion)
|
||||
.add("seq", System.currentTimeMillis())
|
||||
.add("username", username)
|
||||
.render();
|
||||
|
||||
HttpGet httpGet = new HttpGet(url);
|
||||
|
||||
HttpResponse response = httpClient.execute(httpGet);
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
if (HttpStatus.SC_OK != statusCode) {
|
||||
throw new RuntimeException("响应失败(" + statusCode + ")");
|
||||
}
|
||||
|
||||
HttpEntity entity = response.getEntity();
|
||||
byte[] headImgData = EntityUtils.toByteArray(entity);
|
||||
|
||||
return headImgData;
|
||||
} catch (Exception e) {
|
||||
log.error("获取联系人头像图片异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从服务端同步新数据
|
||||
*
|
||||
* @param httpClient http客户端
|
||||
* @param urlVersion url版本号
|
||||
* @param passticket passticket
|
||||
* @param baseRequest BaseRequest
|
||||
* @param syncKey syncKey
|
||||
* @return 返回数据
|
||||
*/
|
||||
public JSONObject webWxSync(HttpClient httpClient,
|
||||
String urlVersion,
|
||||
String passticket,
|
||||
BaseRequest BaseRequest,
|
||||
JSONObject SyncKey) {
|
||||
public static 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)
|
||||
.add("skey", baseRequest.getSkey())
|
||||
.add("sid", baseRequest.getSid())
|
||||
.add("pass_ticket", StringUtil.encodeURL(passticket, Consts.UTF_8.name()))
|
||||
.render();
|
||||
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
httpPost.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
|
||||
|
||||
JSONObject paramJson = new JSONObject();
|
||||
paramJson.put("BaseRequest", BaseRequest);
|
||||
paramJson.put("SyncKey", SyncKey);
|
||||
paramJson.put("BaseRequest", baseRequest);
|
||||
paramJson.put("SyncKey", syncKey);
|
||||
HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8);
|
||||
httpPost.setEntity(paramEntity);
|
||||
|
||||
@@ -547,23 +644,30 @@ public class WebWeixinApi {
|
||||
|
||||
return JSONObject.parseObject(res);
|
||||
} catch (Exception e) {
|
||||
logger.error("从服务端同步新数据异常", e);
|
||||
log.error("从服务端同步新数据异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
*
|
||||
* @param httpClient http客户端
|
||||
* @param urlVersion url版本号
|
||||
* @param passticket passticket
|
||||
* @param baseRequest BaseRequest
|
||||
* @param message 消息
|
||||
* @return 返回数据
|
||||
*/
|
||||
public JSONObject sendMsg(HttpClient httpClient,
|
||||
String urlVersion,
|
||||
String passticket,
|
||||
BaseRequest baseRequest,
|
||||
WxMessage message) {
|
||||
public static 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)
|
||||
.add("pass_ticket", StringUtil.encodeURL(passticket, Consts.UTF_8.name()))
|
||||
.render();
|
||||
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
@@ -585,135 +689,145 @@ public class WebWeixinApi {
|
||||
HttpEntity entity = response.getEntity();
|
||||
String res = EntityUtils.toString(entity, Consts.UTF_8);
|
||||
|
||||
JSONObject result = JSONObject.parseObject(res);
|
||||
|
||||
return result;
|
||||
return JSONObject.parseObject(res);
|
||||
} catch (Exception e) {
|
||||
logger.error("发送消息异常", e);
|
||||
log.error("发送消息异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传媒体文件
|
||||
* 上传媒体文件(支持大文件自动分片上传)
|
||||
*
|
||||
* @return
|
||||
* @param httpClient http客户端
|
||||
* @param urlVersion url版本号
|
||||
* @param passticket passticket
|
||||
* @param baseRequest BaseRequest
|
||||
* @param fromUserName 发送者用户名
|
||||
* @param toUserName 接受者用户名
|
||||
* @param dataTicket dataTicket
|
||||
* @param mediaData 媒体文件二进制数据
|
||||
* @param mediaName 媒体文件名称
|
||||
* @param contentType 媒体文件类型
|
||||
* @param mediaType 媒体类型
|
||||
* @return 返回数据
|
||||
*/
|
||||
public JSONObject uploadMedia(HttpClient httpClient,
|
||||
String urlVersion,
|
||||
String passticket,
|
||||
BaseRequest BaseRequest,
|
||||
String FromUserName,
|
||||
String ToUserName,
|
||||
String dataTicket,
|
||||
byte[] data,
|
||||
String fileName,
|
||||
ContentType contentType) {
|
||||
public static JSONObject uploadMedia(HttpClient httpClient,
|
||||
String urlVersion,
|
||||
String passticket,
|
||||
BaseRequest baseRequest,
|
||||
String fromUserName,
|
||||
String toUserName,
|
||||
String dataTicket,
|
||||
byte[] mediaData,
|
||||
String mediaName,
|
||||
ContentType contentType,
|
||||
MediaType mediaType) {
|
||||
try {
|
||||
String url = new ST(PropertiesUtil.getProperty("webwx-url.uploadmedia_url"))
|
||||
.add("urlVersion", urlVersion)
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传媒体文件
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public JSONObject uploadMedia(HttpClient httpClient,
|
||||
String urlVersion,
|
||||
String passticket,
|
||||
BaseRequest baseRequest,
|
||||
String fromUserName,
|
||||
String toUserName,
|
||||
String dataTicket,
|
||||
File file) {
|
||||
try {
|
||||
String url = new ST(PropertiesUtil.getProperty("webwx-url.uploadmedia_url"))
|
||||
.add("urlVersion", urlVersion)
|
||||
.render();
|
||||
int mediaLength = mediaData.length;
|
||||
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
httpPost.setHeader("Content-type", ContentType.MULTIPART_FORM_DATA.toString());
|
||||
|
||||
long millis = System.currentTimeMillis();
|
||||
String contentTypeStr = new MimetypesFileTypeMap().getContentType(file);
|
||||
ContentType contentType = ContentType.parse(contentTypeStr);
|
||||
|
||||
JSONObject uploadmediarequest = new JSONObject();
|
||||
uploadmediarequest.put("UploadType", 2);
|
||||
uploadmediarequest.put("BaseRequest", baseRequest);
|
||||
uploadmediarequest.put("ClientMediaId", millis);
|
||||
uploadmediarequest.put("TotalLen", file.length());
|
||||
uploadmediarequest.put("TotalLen", mediaLength);
|
||||
uploadmediarequest.put("StartPos", 0);
|
||||
uploadmediarequest.put("DataLen", file.length());
|
||||
uploadmediarequest.put("MediaType", 4);
|
||||
uploadmediarequest.put("DataLen", mediaLength);
|
||||
uploadmediarequest.put(MediaType.REQUEST_JSON_KEY, mediaType.getCode());
|
||||
uploadmediarequest.put("FromUserName", fromUserName);
|
||||
uploadmediarequest.put("ToUserName", toUserName);
|
||||
uploadmediarequest.put("FileMd5", DigestUtils.md5(new FileInputStream(file)));
|
||||
uploadmediarequest.put("FileMd5", DigestUtils.md5Hex(mediaData));
|
||||
|
||||
HttpEntity paramEntity = MultipartEntityBuilder.create()
|
||||
.setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
|
||||
.addTextBody("id", StringUtil.getUuid(), ContentType.TEXT_PLAIN)
|
||||
.addTextBody("name", file.getName(), ContentType.TEXT_PLAIN)
|
||||
.addTextBody("type", contentTypeStr, ContentType.TEXT_PLAIN)
|
||||
.addTextBody("lastModifieDate", millis + "", ContentType.TEXT_PLAIN)
|
||||
.addTextBody("size", file.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", file, contentType, file.getName())
|
||||
.build();
|
||||
// 分片数量
|
||||
int chunks = new BigDecimal(mediaLength).divide(new BigDecimal(UPLOAD_MEDIA_FILE_CHUNK_SIZE), 0, BigDecimal.ROUND_UP).intValue();
|
||||
|
||||
JSONObject result = null;
|
||||
for (int chunk = 0; chunk < chunks; chunk++) {
|
||||
int from = chunk * UPLOAD_MEDIA_FILE_CHUNK_SIZE;
|
||||
int to = (chunk + 1) * UPLOAD_MEDIA_FILE_CHUNK_SIZE;
|
||||
to = Math.min(to, mediaLength);
|
||||
byte[] temp = Arrays.copyOfRange(mediaData, from, to);
|
||||
|
||||
HttpEntity paramEntity = MultipartEntityBuilder.create()
|
||||
.setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
|
||||
.addTextBody("chunks", String.valueOf(chunks))
|
||||
.addTextBody("chunk", String.valueOf(chunk))
|
||||
.addTextBody(MediaType.REQUEST_KEY, mediaType.getValue(), 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", temp, contentType, mediaName)
|
||||
.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);
|
||||
|
||||
result = JSONObject.parseObject(res);
|
||||
if (result == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
JSONObject baseResponse = result.getJSONObject("BaseResponse");
|
||||
if (baseResponse == null) {
|
||||
break;
|
||||
}
|
||||
int ret = baseResponse.getIntValue("Ret");
|
||||
if (ret != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("上传媒体文件异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送图片消息
|
||||
*
|
||||
* @param httpClient http客户端
|
||||
* @param urlVersion url版本号
|
||||
* @param passticket passticket
|
||||
* @param baseRequest BaseRequest
|
||||
* @param message 消息
|
||||
* @return 返回数据
|
||||
*/
|
||||
public static JSONObject sendImageMsg(HttpClient httpClient,
|
||||
String urlVersion,
|
||||
String passticket,
|
||||
BaseRequest baseRequest,
|
||||
MediaMessage message) {
|
||||
try {
|
||||
String url = new ST(PropertiesUtil.getProperty("webwx-url.webwxsendmsgimg_url"))
|
||||
.add("urlVersion", urlVersion)
|
||||
.add("pass_ticket", StringUtil.encodeURL(passticket, Consts.UTF_8.name()))
|
||||
.render();
|
||||
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
httpPost.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
|
||||
|
||||
JSONObject paramJson = new JSONObject();
|
||||
paramJson.put("BaseRequest", baseRequest);
|
||||
paramJson.put("Msg", message);
|
||||
paramJson.put("Scene", 0);
|
||||
HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8);
|
||||
httpPost.setEntity(paramEntity);
|
||||
|
||||
HttpResponse response = httpClient.execute(httpPost);
|
||||
@@ -725,11 +839,53 @@ public class WebWeixinApi {
|
||||
HttpEntity entity = response.getEntity();
|
||||
String res = EntityUtils.toString(entity, Consts.UTF_8);
|
||||
|
||||
JSONObject result = JSONObject.parseObject(res);
|
||||
|
||||
return result;
|
||||
return JSONObject.parseObject(res);
|
||||
} catch (Exception e) {
|
||||
logger.error("上传媒体文件异常", e);
|
||||
log.error("发送图片消息异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送视频消息
|
||||
*
|
||||
* @param httpClient http客户端
|
||||
* @param urlVersion url版本号
|
||||
* @param baseRequest BaseRequest
|
||||
* @param message 消息
|
||||
* @return 返回数据
|
||||
*/
|
||||
public static JSONObject sendVideoMsg(HttpClient httpClient,
|
||||
String urlVersion,
|
||||
BaseRequest baseRequest,
|
||||
MediaMessage message) {
|
||||
try {
|
||||
String url = new ST(PropertiesUtil.getProperty("webwx-url.webwxsendvideomsg_url"))
|
||||
.add("urlVersion", urlVersion)
|
||||
.render();
|
||||
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
httpPost.setHeader("Content-type", ContentType.APPLICATION_JSON.toString());
|
||||
|
||||
JSONObject paramJson = new JSONObject();
|
||||
paramJson.put("BaseRequest", baseRequest);
|
||||
paramJson.put("Msg", message);
|
||||
paramJson.put("Scene", 0);
|
||||
HttpEntity paramEntity = new StringEntity(paramJson.toJSONString(), Consts.UTF_8);
|
||||
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);
|
||||
|
||||
return JSONObject.parseObject(res);
|
||||
} catch (Exception e) {
|
||||
log.error("发送视频消息异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,11 @@ import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
|
||||
/**
|
||||
* 微信工具类
|
||||
*
|
||||
* @author Allen
|
||||
*/
|
||||
public final class WechatUtil {
|
||||
private WechatUtil() {
|
||||
}
|
||||
@@ -14,7 +19,7 @@ public final class WechatUtil {
|
||||
/**
|
||||
* 创建一个设备ID
|
||||
*
|
||||
* @return
|
||||
* @return 设备ID
|
||||
*/
|
||||
public static String createDeviceID() {
|
||||
return "e" + RandomStringUtils.random(15, STRING_CHARS_1);
|
||||
@@ -23,7 +28,7 @@ public final class WechatUtil {
|
||||
/**
|
||||
* 创建一个消息ID
|
||||
*
|
||||
* @return
|
||||
* @return 消息ID
|
||||
*/
|
||||
public static String createMsgId() {
|
||||
return System.currentTimeMillis() + RandomStringUtils.random(4, STRING_CHARS_2);
|
||||
@@ -32,8 +37,8 @@ public final class WechatUtil {
|
||||
/**
|
||||
* 把SyncKeyList转为字符串格式
|
||||
*
|
||||
* @param SyncKeyList
|
||||
* @return
|
||||
* @param SyncKeyList SyncKeyList
|
||||
* @return 字符串
|
||||
*/
|
||||
public static String syncKeyListToString(JSONArray SyncKeyList) {
|
||||
if (SyncKeyList == null) {
|
||||
@@ -51,21 +56,4 @@ public final class WechatUtil {
|
||||
}
|
||||
return synckey.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ContentType得到微信上传所需的mediatype
|
||||
*
|
||||
* @param contentType
|
||||
* @return
|
||||
*/
|
||||
public static String getMediatype(String contentType) {
|
||||
if (contentType == null) {
|
||||
return "doc";
|
||||
}
|
||||
if (contentType.indexOf("image") >= 0) {
|
||||
return "pic";
|
||||
} else {
|
||||
return "doc";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# 0、全局
|
||||
## 0.1、Web微信host
|
||||
webwx-url.webwxhost_url=https://wx<urlVersion>.qq.com
|
||||
# 1、登录
|
||||
## 1.1、获取微信uuid
|
||||
webwx-url.uuid_url=https://login.wx.qq.com/jslogin?appid=<appid>&fun=new&lang=zh_CN&_=<_>
|
||||
@@ -23,10 +26,16 @@ webwx-url.synccheck_url=https://webpush.wx<urlVersion>.qq.com/cgi-bin/mmwebwx-bi
|
||||
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://wx<urlVersion>.qq.com/cgi-bin/mmwebwx-bin/webwxbatchgetcontact?type=ex&r=<r>&lang=zh_CN&pass_ticket=<pass_ticket>
|
||||
## 3.3、获取联系人头像
|
||||
webwx-url.webwxgetheadimg_url=https://wx<urlVersion>.qq.com/cgi-bin/mmwebwx-bin/webwxgetheadimg?seq=<seq>&username=<username>
|
||||
# 4、收发消息
|
||||
## 4.1、从服务端拉取新消息
|
||||
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://wx<urlVersion>.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket=<pass_ticket>
|
||||
## 4.3、上传媒体文件
|
||||
webwx-url.uploadmedia_url=https://file.wx<urlVersion>.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
|
||||
## 4.4、发送图片消息
|
||||
webwx-url.webwxsendmsgimg_url=https://wx<urlVersion>.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsgimg?fun=async&f=json&lang=zh_CN&pass_ticket=<pass_ticket>
|
||||
## 4.5、发送视频消息
|
||||
webwx-url.webwxsendvideomsg_url=https://wx<urlVersion>.qq.com/cgi-bin/mmwebwx-bin/webwxsendvideomsg?fun=async&f=json
|
||||
@@ -1,15 +1,24 @@
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.hotlcc.wechat4j.Wechat;
|
||||
import com.hotlcc.wechat4j.api.WebWeixinApi;
|
||||
import com.hotlcc.wechat4j.handler.ReceivedMsgHandler;
|
||||
import com.hotlcc.wechat4j.model.ReceivedMsg;
|
||||
import com.hotlcc.wechat4j.model.UserInfo;
|
||||
import com.hotlcc.wechat4j.util.CommonUtil;
|
||||
import com.hotlcc.wechat4j.util.StringUtil;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class TestClass {
|
||||
public static void main(String[] args) {
|
||||
WebWeixinApi api = new WebWeixinApi();
|
||||
Wechat wechat = new Wechat();
|
||||
wechat.setWebWeixinApi(api);
|
||||
private Wechat wechat;
|
||||
|
||||
@Before
|
||||
public void initAndLogin() {
|
||||
wechat = new Wechat();
|
||||
wechat.addReceivedMsgHandler(new ReceivedMsgHandler() {
|
||||
@Override
|
||||
public void handleAllType(Wechat wechat, ReceivedMsg msg) {
|
||||
@@ -18,6 +27,46 @@ public class TestClass {
|
||||
System.out.println(name + ": " + msg.getContent());
|
||||
}
|
||||
});
|
||||
|
||||
wechat.autoLogin();
|
||||
}
|
||||
|
||||
public void testSendText() {
|
||||
JSONObject result = wechat.sendTextToUserName(null, "这是消息内容");
|
||||
System.out.println(result);
|
||||
}
|
||||
|
||||
public void testSendImage() {
|
||||
File file = null;
|
||||
JSONObject result = null;
|
||||
file = new File("C:\\Users\\Administrator\\Pictures\\壁纸\\9e5f4981099bcf351e0ec18c3654aced.jpg");
|
||||
result = wechat.sendImageToUserName(null, file);
|
||||
file = new File("C:\\Users\\Administrator\\Videos\\手机QQ视频_20190416170016.mp4");
|
||||
result = wechat.sendVideoToUserName(null, file);
|
||||
System.out.println(result);
|
||||
while (true) CommonUtil.threadSleep(5000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetImageData() {
|
||||
byte[] data = wechat.getContactHeadImgByUserName(null);
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream("D:\\a.jpg");
|
||||
fos.write(data);
|
||||
fos.flush();
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (fos != null) {
|
||||
try {
|
||||
fos.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user