├── README.md
├── src
├── main
│ ├── java
│ │ ├── META-INF
│ │ │ └── MANIFEST.MF
│ │ └── top
│ │ │ └── itning
│ │ │ ├── webqq
│ │ │ ├── model
│ │ │ │ ├── Recent.java
│ │ │ │ ├── Birthday.java
│ │ │ │ ├── Discuss.java
│ │ │ │ ├── DiscussInfo.java
│ │ │ │ ├── FriendStatus.java
│ │ │ │ ├── Group.java
│ │ │ │ ├── DiscussUser.java
│ │ │ │ ├── Friend.java
│ │ │ │ ├── Font.java
│ │ │ │ ├── Category.java
│ │ │ │ ├── GroupInfo.java
│ │ │ │ ├── Message.java
│ │ │ │ ├── DiscussMessage.java
│ │ │ │ ├── GroupMessage.java
│ │ │ │ ├── GroupUser.java
│ │ │ │ └── UserInfo.java
│ │ │ ├── callback
│ │ │ │ └── MessageCallback.java
│ │ │ ├── constant
│ │ │ │ └── ApiURL.java
│ │ │ └── client
│ │ │ │ └── SmartQQClient.java
│ │ │ ├── util
│ │ │ └── PropertiesUtil.java
│ │ │ ├── curriculum
│ │ │ ├── CurriculumClient.java
│ │ │ └── CurriculumEnum.java
│ │ │ ├── weather
│ │ │ ├── entity
│ │ │ │ ├── Weather.java
│ │ │ │ ├── WeatherData.java
│ │ │ │ └── WeatherInfo.java
│ │ │ └── client
│ │ │ │ └── WeatherInfoClient.java
│ │ │ ├── Application.java
│ │ │ └── timer
│ │ │ └── TimerTasks.java
│ └── resources
│ │ └── log4j.properties
└── test
│ └── java
│ └── Test.java
├── configurationInfo.properties
├── .gitignore
├── LICENSE
└── pom.xml
/README.md:
--------------------------------------------------------------------------------
1 | # QQrobot
2 | QQ机器人
3 |
--------------------------------------------------------------------------------
/src/main/java/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Main-Class: top.itning.Application
3 |
4 |
--------------------------------------------------------------------------------
/configurationInfo.properties:
--------------------------------------------------------------------------------
1 | #管理员QQ昵称
2 | adminName=她姓许º
3 | #需要发送消息的群昵称
4 | groupName=╭ァ編徎縱扖門到瓬棄
5 | #关闭命令
6 | close_command=close
7 | #每次执行时间间隔(ms) 24 * 60 * 60 * 1000
8 | time_period=8640000
9 | #时间
10 | run_time=21:21:0
--------------------------------------------------------------------------------
/src/main/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=INFO,stdout
2 |
3 | #Console Appender
4 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
5 | log4j.appender.stdout.Target=System.out
6 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
7 | log4j.appender.stdout.layout.ConversionPattern=%c %x - %m%n
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Java template
3 | # Compiled class file
4 | *.class
5 |
6 | # Log file
7 | *.log
8 |
9 | # BlueJ files
10 | *.ctxt
11 |
12 | # Mobile Tools for Java (J2ME)
13 | .mtj.tmp/
14 |
15 | # Package Files #
16 | *.jar
17 | *.war
18 | *.ear
19 | *.zip
20 | *.tar.gz
21 | *.rar
22 |
23 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
24 | hs_err_pid*
25 |
26 | .idea/
27 | Qqrobot.iml
28 | out/artifacts/Qqrobot_jar/qrcode.png
29 | qrcode.png
30 | target/classes/log4j.properties
31 | target/generated-sources/
32 | target/generated-test-sources/
33 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/webqq/model/Recent.java:
--------------------------------------------------------------------------------
1 | package top.itning.webqq.model;
2 |
3 | /**
4 | * 最近会话.
5 | *
6 | * @author ScienJus
7 | * @author Liang Ding
8 | * @date 2015/12/24.
9 | */
10 | public class Recent {
11 |
12 | private long uin;
13 |
14 | //0:好友、1:群、2:讨论组
15 | private int type;
16 |
17 | public long getUin() {
18 | return uin;
19 | }
20 |
21 | public void setUin(long uin) {
22 | this.uin = uin;
23 | }
24 |
25 | public int getType() {
26 | return type;
27 | }
28 |
29 | public void setType(int type) {
30 | this.type = type;
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/webqq/callback/MessageCallback.java:
--------------------------------------------------------------------------------
1 | package top.itning.webqq.callback;
2 |
3 |
4 | import top.itning.webqq.model.DiscussMessage;
5 | import top.itning.webqq.model.GroupMessage;
6 | import top.itning.webqq.model.Message;
7 |
8 | /**
9 | * 收到消息的回调
10 | * @author ScienJus
11 | * @date 2015/12/18.
12 | */
13 | public interface MessageCallback {
14 |
15 | /**
16 | * 收到私聊消息后的回调
17 | * @param message 私聊消息
18 | */
19 | void onMessage(Message message);
20 |
21 | /**
22 | * 收到群消息后的回调
23 | * @param message 群消息
24 | */
25 | void onGroupMessage(GroupMessage message);
26 |
27 | /**
28 | * 收到讨论组消息后的回调
29 | * @param message 讨论组消息
30 | */
31 | void onDiscussMessage(DiscussMessage message);
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/webqq/model/Birthday.java:
--------------------------------------------------------------------------------
1 | package top.itning.webqq.model;
2 |
3 | /**
4 | * 生日.
5 | *
6 | * @author ScienJus
7 | * @author Liang Ding
8 | * @date 2015/12/24.
9 | */
10 | public class Birthday {
11 |
12 | private int year;
13 |
14 | private int month;
15 |
16 | private int day;
17 |
18 | public int getYear() {
19 | return year;
20 | }
21 |
22 | public void setYear(int year) {
23 | this.year = year;
24 | }
25 |
26 | public int getMonth() {
27 | return month;
28 | }
29 |
30 | public void setMonth(int month) {
31 | this.month = month;
32 | }
33 |
34 | public int getDay() {
35 | return day;
36 | }
37 |
38 | public void setDay(int day) {
39 | this.day = day;
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/util/PropertiesUtil.java:
--------------------------------------------------------------------------------
1 | package top.itning.util;
2 |
3 | import java.io.*;
4 | import java.util.Properties;
5 |
6 | /***
7 | *
8 | * @author : ning
9 | * @version : 1.0.0
10 | * @date : 2017/11/7
11 | **/
12 | public class PropertiesUtil {
13 | private final static Properties PROPERTIES = new Properties();
14 |
15 | private PropertiesUtil() {
16 | }
17 |
18 | public static String getValueByKey(String key, String url) {
19 | if (key != null) {
20 | try {
21 | //PROPERTIES.load(new FileReader(""));
22 | PROPERTIES.load(new InputStreamReader(new FileInputStream(url),"utf-8"));
23 | } catch (IOException e) {
24 | System.err.println("url error");
25 | e.printStackTrace();
26 | }
27 | return PROPERTIES.getProperty(key);
28 | }
29 | return null;
30 | }
31 | }
--------------------------------------------------------------------------------
/src/main/java/top/itning/webqq/model/Discuss.java:
--------------------------------------------------------------------------------
1 | package top.itning.webqq.model;
2 |
3 | import com.alibaba.fastjson.annotation.JSONField;
4 |
5 | /**
6 | * 讨论组.
7 | *
8 | * @author ScienJus
9 | * @author Liang Ding
10 | * @date 2015/12/23.
11 | */
12 | public class Discuss {
13 |
14 | @JSONField(name = "did")
15 | private long id;
16 |
17 | private String name;
18 |
19 | public long getId() {
20 | return id;
21 | }
22 |
23 | public void setId(long id) {
24 | this.id = id;
25 | }
26 |
27 | public String getName() {
28 | return name;
29 | }
30 |
31 | public void setName(String name) {
32 | this.name = name;
33 | }
34 |
35 | @Override
36 | public String toString() {
37 | return "Discuss{" +
38 | "id=" + id +
39 | ", name='" + name + '\'' +
40 | '}';
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 a1837634447
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/webqq/model/DiscussInfo.java:
--------------------------------------------------------------------------------
1 | package top.itning.webqq.model;
2 |
3 | import com.alibaba.fastjson.annotation.JSONField;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | /**
9 | * 讨论组资料.
10 | *
11 | * @author ScienJus
12 | * @author Liang Ding
13 | * @date 2015/12/24.
14 | */
15 | public class DiscussInfo {
16 |
17 | @JSONField(name = "did")
18 | private long id;
19 |
20 | @JSONField(name = "discu_name")
21 | private String name;
22 |
23 | private List users = new ArrayList<>();
24 |
25 | public void addUser(DiscussUser user) {
26 | this.users.add(user);
27 | }
28 |
29 | public long getId() {
30 | return id;
31 | }
32 |
33 | public void setId(long id) {
34 | this.id = id;
35 | }
36 |
37 | public String getName() {
38 | return name;
39 | }
40 |
41 | public void setName(String name) {
42 | this.name = name;
43 | }
44 |
45 | public List getUsers() {
46 | return users;
47 | }
48 |
49 | public void setUsers(List users) {
50 | this.users = users;
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/webqq/model/FriendStatus.java:
--------------------------------------------------------------------------------
1 | package top.itning.webqq.model;
2 |
3 | import com.alibaba.fastjson.annotation.JSONField;
4 |
5 | /**
6 | * 好友状态.
7 | *
8 | * @author ScienJus
9 | * @author Liang Ding
10 | * @date 2015/12/24.
11 | */
12 | public class FriendStatus {
13 |
14 | private long uin;
15 |
16 | private String status;
17 |
18 | @JSONField(name = "client_type")
19 | private int clientType;
20 |
21 | public long getUin() {
22 | return uin;
23 | }
24 |
25 | public void setUin(long uin) {
26 | this.uin = uin;
27 | }
28 |
29 | public String getStatus() {
30 | return status;
31 | }
32 |
33 | public void setStatus(String status) {
34 | this.status = status;
35 | }
36 |
37 | public int getClientType() {
38 | return clientType;
39 | }
40 |
41 | public void setClientType(int clientType) {
42 | this.clientType = clientType;
43 | }
44 |
45 | @Override
46 | public String toString() {
47 | return "FriendStatus{" +
48 | "uin=" + uin +
49 | ", status='" + status + '\'' +
50 | ", clientType=" + clientType +
51 | '}';
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/curriculum/CurriculumClient.java:
--------------------------------------------------------------------------------
1 | package top.itning.curriculum;
2 |
3 | import java.text.SimpleDateFormat;
4 | import java.util.Date;
5 | import java.util.Locale;
6 |
7 | /**
8 | * @author wangn
9 | */
10 | public class CurriculumClient {
11 | private CurriculumClient() {
12 | }
13 |
14 | public static String getClassInfo() {
15 | String day = new SimpleDateFormat("EE", Locale.US).format(new Date());
16 | String info = "";
17 | switch (day) {
18 | case "Mon":
19 | info = CurriculumEnum.Monday.getClassInfo();
20 | break;
21 | case "Tue":
22 | info = CurriculumEnum.Tuesday.getClassInfo();
23 | break;
24 | case "Wed":
25 | info = CurriculumEnum.Wednesday.getClassInfo();
26 | break;
27 | case "Thu":
28 | info = CurriculumEnum.Thursday.getClassInfo();
29 | break;
30 | case "Fri":
31 | info = CurriculumEnum.Friday.getClassInfo();
32 | break;
33 | default:
34 | }
35 | return ((!"星期六".equals(day)) ? "今天课程:\n" : "") + info + (("星期五".equals(day) || "星期六".equals(day)) ? "" : "晚自习:A301");
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/webqq/model/Group.java:
--------------------------------------------------------------------------------
1 | package top.itning.webqq.model;
2 |
3 | import com.alibaba.fastjson.annotation.JSONField;
4 |
5 | /**
6 | * 群.
7 | *
8 | * @author ScienJus
9 | * @author Liang Ding
10 | * @date 2015/12/18.
11 | */
12 | public class Group {
13 |
14 | @JSONField(name = "gid")
15 | private long id;
16 |
17 | private String name;
18 |
19 | private long flag;
20 |
21 | private long code;
22 |
23 | public long getId() {
24 | return id;
25 | }
26 |
27 | public void setId(long id) {
28 | this.id = id;
29 | }
30 |
31 | public String getName() {
32 | return name;
33 | }
34 |
35 | public void setName(String name) {
36 | this.name = name;
37 | }
38 |
39 | public long getFlag() {
40 | return flag;
41 | }
42 |
43 | public void setFlag(long flag) {
44 | this.flag = flag;
45 | }
46 |
47 | public long getCode() {
48 | return code;
49 | }
50 |
51 | public void setCode(long code) {
52 | this.code = code;
53 | }
54 |
55 | @Override
56 | public String toString() {
57 | return "Group{" +
58 | "id=" + id +
59 | ", name='" + name + '\'' +
60 | ", flag=" + flag +
61 | ", code=" + code +
62 | '}';
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/webqq/model/DiscussUser.java:
--------------------------------------------------------------------------------
1 | package top.itning.webqq.model;
2 |
3 | /**
4 | * 讨论组成员.
5 | *
6 | * @author ScienJus
7 | * @author Liang Ding
8 | * @date 2015/12/24.
9 | */
10 | public class DiscussUser {
11 |
12 | private long uin;
13 |
14 | private String nick;
15 |
16 | private int clientType;
17 |
18 | private String status;
19 |
20 | @Override
21 | public String toString() {
22 | return "DiscussUser{"
23 | + "uin=" + uin
24 | + ", nick='" + nick + '\''
25 | + ", clientType='" + clientType + '\''
26 | + ", status='" + status + '\''
27 | + '}';
28 | }
29 |
30 | public long getUin() {
31 | return uin;
32 | }
33 |
34 | public void setUin(long uin) {
35 | this.uin = uin;
36 | }
37 |
38 | public String getNick() {
39 | return nick;
40 | }
41 |
42 | public void setNick(String nick) {
43 | this.nick = nick;
44 | }
45 |
46 | public int getClientType() {
47 | return clientType;
48 | }
49 |
50 | public void setClientType(int clientType) {
51 | this.clientType = clientType;
52 | }
53 |
54 | public String getStatus() {
55 | return status;
56 | }
57 |
58 | public void setStatus(String status) {
59 | this.status = status;
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/curriculum/CurriculumEnum.java:
--------------------------------------------------------------------------------
1 | package top.itning.curriculum;
2 |
3 | /**
4 | * @author wangn
5 | */
6 | public enum CurriculumEnum {
7 | Monday(
8 | "",
9 | "三四节:篮球 外聘2 地点:篮球场",
10 | "五六节:互联网程序设计 梁海红 地点:B313",
11 | "七八节:英语四六级 李鑫 地点:A301"
12 | ),
13 | Tuesday(
14 | "一二节:英语四六级 李鑫 地点:A301",
15 | "三四节:线性代数 徐延新 地点:A330",
16 | "",
17 | ""
18 | ),
19 | Wednesday(
20 | "一二节:互联网程序设计 梁海红 地点:B313",
21 | "三四节:JAVA程序设计 于洪 地点:B202",
22 | "五六节:模电数电 华晓杰 地点:B313",
23 | ""
24 | ),
25 | Thursday(
26 | "一二节:计算机组成原理 夏庆英 地点:B312",
27 | "三四节:线性代数 徐延新 地点:A401",
28 | "五六节:JAVA程序设计 于洪 地点:B317",
29 | "五六节:计算机组成原理 夏庆英 地点:B211"
30 | ),
31 | Friday(
32 | "一二节:模电数电 华晓杰 地点:A221",
33 | "",
34 | "",
35 | ""
36 | );
37 |
38 | private String class1;
39 | private String class2;
40 | private String class3;
41 | private String class4;
42 |
43 | CurriculumEnum(String class1, String class2, String class3, String class4) {
44 | this.class1 = class1;
45 | this.class2 = class2;
46 | this.class3 = class3;
47 | this.class4 = class4;
48 | }
49 |
50 | public String getClassInfo() {
51 | return class1 + "\n" + class2 + "\n" + class3 + "\n" + class4 + "\n";
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/webqq/model/Friend.java:
--------------------------------------------------------------------------------
1 | package top.itning.webqq.model;
2 |
3 | /**
4 | * 好友.
5 | *
6 | * @author ScienJus
7 | * @author Liang Ding
8 | * @date 2015/12/18.
9 | */
10 | public class Friend {
11 |
12 | private long userId;
13 |
14 | private String markname = "";
15 |
16 | private String nickname;
17 |
18 | private boolean vip;
19 |
20 | private int vipLevel;
21 |
22 | @Override
23 | public String toString() {
24 | return "Friend{"
25 | + "userId=" + userId
26 | + ", markname='" + markname + '\''
27 | + ", nickname='" + nickname + '\''
28 | + ", vip=" + vip
29 | + ", vipLevel=" + vipLevel
30 | + '}';
31 | }
32 |
33 | public long getUserId() {
34 | return userId;
35 | }
36 |
37 | public void setUserId(long userId) {
38 | this.userId = userId;
39 | }
40 |
41 | public String getMarkname() {
42 | return markname;
43 | }
44 |
45 | public void setMarkname(String markname) {
46 | this.markname = markname;
47 | }
48 |
49 | public String getNickname() {
50 | return nickname;
51 | }
52 |
53 | public void setNickname(String nickname) {
54 | this.nickname = nickname;
55 | }
56 |
57 | public boolean isVip() {
58 | return vip;
59 | }
60 |
61 | public void setVip(boolean vip) {
62 | this.vip = vip;
63 | }
64 |
65 | public int getVipLevel() {
66 | return vipLevel;
67 | }
68 |
69 | public void setVipLevel(int vipLevel) {
70 | this.vipLevel = vipLevel;
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/webqq/model/Font.java:
--------------------------------------------------------------------------------
1 | package top.itning.webqq.model;
2 |
3 | import java.util.Arrays;
4 |
5 | /**
6 | * 字体.
7 | *
8 | * @author ScienJus
9 | * @author Liang Ding
10 | * @date 15/12/19.
11 | */
12 | public class Font {
13 |
14 | public static final Font DEFAULT_FONT = defaultFont();
15 |
16 | private static Font defaultFont() {
17 | Font font = new Font();
18 | font.setColor("000000");
19 | font.setStyle(new int[]{0, 0, 0});
20 | font.setName("宋体");
21 | font.setSize(10);
22 | return font;
23 | }
24 |
25 | private int[] style;
26 |
27 | private String color;
28 |
29 | private String name;
30 |
31 | private int size;
32 |
33 | public int[] getStyle() {
34 | return style;
35 | }
36 |
37 | public void setStyle(int[] style) {
38 | this.style = style;
39 | }
40 |
41 | public String getColor() {
42 | return color;
43 | }
44 |
45 | public void setColor(String color) {
46 | this.color = color;
47 | }
48 |
49 | public String getName() {
50 | return name;
51 | }
52 |
53 | public void setName(String name) {
54 | this.name = name;
55 | }
56 |
57 | public int getSize() {
58 | return size;
59 | }
60 |
61 | public void setSize(int size) {
62 | this.size = size;
63 | }
64 |
65 | @Override
66 | public String toString() {
67 | return "Font{" +
68 | "style=" + Arrays.toString(style) +
69 | ", color='" + color + '\'' +
70 | ", name='" + name + '\'' +
71 | ", size=" + size +
72 | '}';
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/webqq/model/Category.java:
--------------------------------------------------------------------------------
1 | package top.itning.webqq.model;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | /**
7 | * 分组.
8 | *
9 | * @author ScienJus
10 | * @author Liang Ding
11 | * @date 15/12/19.
12 | */
13 | public class Category {
14 |
15 | private int index;
16 |
17 | private int sort;
18 |
19 | private String name;
20 |
21 | private List friends = new ArrayList<>();
22 |
23 | public void addFriend(Friend friend) {
24 | this.friends.add(friend);
25 | }
26 |
27 | @Override
28 | public String toString() {
29 | return "Category{"
30 | + "index=" + index
31 | + ", sort=" + sort
32 | + ", name='" + name + '\''
33 | + ", friends=" + friends
34 | + '}';
35 | }
36 |
37 | public static Category defaultCategory() {
38 | Category category = new Category();
39 | category.setIndex(0);
40 | category.setSort(0);
41 | category.setName("我的好友");
42 | return category;
43 | }
44 |
45 | public int getIndex() {
46 | return index;
47 | }
48 |
49 | public void setIndex(int index) {
50 | this.index = index;
51 | }
52 |
53 | public int getSort() {
54 | return sort;
55 | }
56 |
57 | public void setSort(int sort) {
58 | this.sort = sort;
59 | }
60 |
61 | public String getName() {
62 | return name;
63 | }
64 |
65 | public void setName(String name) {
66 | this.name = name;
67 | }
68 |
69 | public List getFriends() {
70 | return friends;
71 | }
72 |
73 | public void setFriends(List friends) {
74 | this.friends = friends;
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/weather/entity/Weather.java:
--------------------------------------------------------------------------------
1 | package top.itning.weather.entity;
2 |
3 | /***
4 | *
5 | * @author : ning
6 | * @version : 1.0.0
7 | * @date : 2017/11/7
8 | **/
9 | public class Weather {
10 | private String date;
11 | private String message;
12 | private Integer status;
13 | private String city;
14 | private Integer count;
15 | private WeatherData data;
16 |
17 | public String getDate() {
18 | return date;
19 | }
20 |
21 | public void setDate(String date) {
22 | this.date = date;
23 | }
24 |
25 | public String getMessage() {
26 | return message;
27 | }
28 |
29 | public void setMessage(String message) {
30 | this.message = message;
31 | }
32 |
33 | public Integer getStatus() {
34 | return status;
35 | }
36 |
37 | public void setStatus(Integer status) {
38 | this.status = status;
39 | }
40 |
41 | public String getCity() {
42 | return city;
43 | }
44 |
45 | public void setCity(String city) {
46 | this.city = city;
47 | }
48 |
49 | public Integer getCount() {
50 | return count;
51 | }
52 |
53 | public void setCount(Integer count) {
54 | this.count = count;
55 | }
56 |
57 | public WeatherData getData() {
58 | return data;
59 | }
60 |
61 | public void setData(WeatherData data) {
62 | this.data = data;
63 | }
64 |
65 | @Override
66 | public String toString() {
67 | return "Weather{" +
68 | "date='" + date + '\'' +
69 | ", message='" + message + '\'' +
70 | ", status=" + status +
71 | ", city='" + city + '\'' +
72 | ", count=" + count +
73 | ", data=" + data +
74 | '}';
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/webqq/model/GroupInfo.java:
--------------------------------------------------------------------------------
1 | package top.itning.webqq.model;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | /**
7 | * 群资料.
8 | *
9 | * @author ScienJus
10 | * @author Liang Ding
11 | * @date 2015/12/24.
12 | */
13 | public class GroupInfo {
14 |
15 | private long gid;
16 |
17 | private long createtime;
18 |
19 | private String memo;
20 |
21 | private String name;
22 |
23 | private long owner;
24 |
25 | private String markname;
26 |
27 | private List users = new ArrayList<>();
28 |
29 | public void addUser(GroupUser user) {
30 | this.users.add(user);
31 | }
32 |
33 | public long getGid() {
34 | return gid;
35 | }
36 |
37 | public void setGid(long gid) {
38 | this.gid = gid;
39 | }
40 |
41 | public long getCreatetime() {
42 | return createtime;
43 | }
44 |
45 | public void setCreatetime(long createtime) {
46 | this.createtime = createtime;
47 | }
48 |
49 | public String getMemo() {
50 | return memo;
51 | }
52 |
53 | public void setMemo(String memo) {
54 | this.memo = memo;
55 | }
56 |
57 | public String getName() {
58 | return name;
59 | }
60 |
61 | public void setName(String name) {
62 | this.name = name;
63 | }
64 |
65 | public long getOwner() {
66 | return owner;
67 | }
68 |
69 | public void setOwner(long owner) {
70 | this.owner = owner;
71 | }
72 |
73 | public String getMarkname() {
74 | return markname;
75 | }
76 |
77 | public void setMarkname(String markname) {
78 | this.markname = markname;
79 | }
80 |
81 | public List getUsers() {
82 | return users;
83 | }
84 |
85 | public void setUsers(List users) {
86 | this.users = users;
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/webqq/model/Message.java:
--------------------------------------------------------------------------------
1 | package top.itning.webqq.model;
2 |
3 | import com.alibaba.fastjson.JSONArray;
4 | import com.alibaba.fastjson.JSONObject;
5 |
6 | /**
7 | * 消息.
8 | *
9 | * @author ScienJus
10 | * @author Liang Ding
11 | * @date 15/12/19.
12 | */
13 | public class Message {
14 |
15 | private long time;
16 |
17 | private String content;
18 |
19 | private long userId;
20 |
21 | private Font font;
22 |
23 | public Message(JSONObject json) {
24 | JSONArray cont = json.getJSONArray("content");
25 | this.font = cont.getJSONArray(0).getObject(1, Font.class);
26 |
27 | final int size = cont.size();
28 | final StringBuilder contentBuilder = new StringBuilder();
29 | for (int i = 1; i < size; i++) {
30 | contentBuilder.append(cont.getString(i));
31 | }
32 | this.content = contentBuilder.toString();
33 |
34 | this.time = json.getLongValue("time");
35 | this.userId = json.getLongValue("from_uin");
36 | }
37 |
38 | public long getTime() {
39 | return time;
40 | }
41 |
42 | public void setTime(long time) {
43 | this.time = time;
44 | }
45 |
46 | public String getContent() {
47 | return content;
48 | }
49 |
50 | public void setContent(String content) {
51 | this.content = content;
52 | }
53 |
54 | public long getUserId() {
55 | return userId;
56 | }
57 |
58 | public void setUserId(long userId) {
59 | this.userId = userId;
60 | }
61 |
62 | public Font getFont() {
63 | return font;
64 | }
65 |
66 | public void setFont(Font font) {
67 | this.font = font;
68 | }
69 |
70 | @Override
71 | public String toString() {
72 | return "Message{" +
73 | "time=" + time +
74 | ", content='" + content + '\'' +
75 | ", userId=" + userId +
76 | ", font=" + font +
77 | '}';
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | top.itning
8 | qqrobot
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 | org.apache.maven.plugins
14 | maven-compiler-plugin
15 |
16 | 1.6
17 | 1.6
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | junit
27 | junit
28 | 4.12
29 | test
30 |
31 |
32 |
33 | log4j
34 | log4j
35 | 1.2.17
36 |
37 |
38 |
39 | com.alibaba
40 | fastjson
41 | 1.2.7
42 |
43 |
44 |
45 | net.dongliu
46 | requests
47 | 2.1.5
48 |
49 |
50 |
51 |
52 | com.google.guava
53 | guava
54 | 23.3-jre
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/weather/entity/WeatherData.java:
--------------------------------------------------------------------------------
1 | package top.itning.weather.entity;
2 |
3 | import java.util.Arrays;
4 |
5 | /**
6 | * @author wangn
7 | */
8 | public class WeatherData {
9 | private String shidu;
10 | private Integer pm25;
11 | private Integer pm10;
12 | private String quality;
13 | private String wendu;
14 | private String ganmao;
15 | private WeatherInfo[] forecast;
16 |
17 | public String getShidu() {
18 | return shidu;
19 | }
20 |
21 | public void setShidu(String shidu) {
22 | this.shidu = shidu;
23 | }
24 |
25 | public Integer getPm25() {
26 | return pm25;
27 | }
28 |
29 | public void setPm25(Integer pm25) {
30 | this.pm25 = pm25;
31 | }
32 |
33 | public Integer getPm10() {
34 | return pm10;
35 | }
36 |
37 | public void setPm10(Integer pm10) {
38 | this.pm10 = pm10;
39 | }
40 |
41 | public String getQuality() {
42 | return quality;
43 | }
44 |
45 | public void setQuality(String quality) {
46 | this.quality = quality;
47 | }
48 |
49 | public String getWendu() {
50 | return wendu;
51 | }
52 |
53 | public void setWendu(String wendu) {
54 | this.wendu = wendu;
55 | }
56 |
57 | public String getGanmao() {
58 | return ganmao;
59 | }
60 |
61 | public void setGanmao(String ganmao) {
62 | this.ganmao = ganmao;
63 | }
64 |
65 | public WeatherInfo[] getForecast() {
66 | return forecast;
67 | }
68 |
69 | public void setForecast(WeatherInfo[] forecast) {
70 | this.forecast = forecast;
71 | }
72 |
73 | @Override
74 | public String toString() {
75 | return "WeatherData{" +
76 | "shidu='" + shidu + '\'' +
77 | ", pm25=" + pm25 +
78 | ", pm10=" + pm10 +
79 | ", quality='" + quality + '\'' +
80 | ", wendu='" + wendu + '\'' +
81 | ", ganmao='" + ganmao + '\'' +
82 | ", forecast=" + Arrays.toString(forecast) +
83 | '}';
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/webqq/model/DiscussMessage.java:
--------------------------------------------------------------------------------
1 | package top.itning.webqq.model;
2 |
3 | import com.alibaba.fastjson.JSONArray;
4 | import com.alibaba.fastjson.JSONObject;
5 |
6 | /**
7 | * 讨论组消息.
8 | *
9 | * @author ScienJus
10 | * @author Liang Ding
11 | * @date 15/12/19.
12 | */
13 | public class DiscussMessage {
14 |
15 | private long discussId;
16 |
17 | private long time;
18 |
19 | private String content;
20 |
21 | private long userId;
22 |
23 | private Font font;
24 |
25 | public DiscussMessage(JSONObject json) {
26 | JSONArray content = json.getJSONArray("content");
27 | this.font = content.getJSONArray(0).getObject(1, Font.class);
28 | this.content = content.getString(1);
29 | if (content.size() > 2)
30 | this.content += content.getString(3);
31 | this.time = json.getLongValue("time");
32 | this.discussId = json.getLongValue("did");
33 | this.userId = json.getLongValue("send_uin");
34 | }
35 |
36 | public long getDiscussId() {
37 | return discussId;
38 | }
39 |
40 | public void setDiscussId(long discussId) {
41 | this.discussId = discussId;
42 | }
43 |
44 | public long getTime() {
45 | return time;
46 | }
47 |
48 | public void setTime(long time) {
49 | this.time = time;
50 | }
51 |
52 | public String getContent() {
53 | return content;
54 | }
55 |
56 | public void setContent(String content) {
57 | this.content = content;
58 | }
59 |
60 | public long getUserId() {
61 | return userId;
62 | }
63 |
64 | public void setUserId(long userId) {
65 | this.userId = userId;
66 | }
67 |
68 | public Font getFont() {
69 | return font;
70 | }
71 |
72 | public void setFont(Font font) {
73 | this.font = font;
74 | }
75 |
76 | @Override
77 | public String toString() {
78 | return "DiscussMessage{" +
79 | "discussId=" + discussId +
80 | ", time=" + time +
81 | ", content='" + content + '\'' +
82 | ", userId=" + userId +
83 | ", font=" + font +
84 | '}';
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/webqq/model/GroupMessage.java:
--------------------------------------------------------------------------------
1 | package top.itning.webqq.model;
2 |
3 | import com.alibaba.fastjson.JSONArray;
4 | import com.alibaba.fastjson.JSONObject;
5 |
6 | /**
7 | * 群消息.
8 | *
9 | * @author ScienJus
10 | * @author Liang Ding
11 | * @date 15/12/19.
12 | */
13 | public class GroupMessage {
14 |
15 | private long groupId;
16 |
17 | private long time;
18 |
19 | private String content;
20 |
21 | private long userId;
22 |
23 | private Font font;
24 |
25 | public GroupMessage(JSONObject json) {
26 | JSONArray cont = json.getJSONArray("content");
27 | this.font = cont.getJSONArray(0).getObject(1, Font.class);
28 |
29 | final int size = cont.size();
30 | final StringBuilder contentBuilder = new StringBuilder();
31 | for (int i = 1; i < size; i++) {
32 | contentBuilder.append(cont.getString(i));
33 | }
34 | this.content = contentBuilder.toString();
35 |
36 | this.time = json.getLongValue("time");
37 | this.groupId = json.getLongValue("group_code");
38 | this.userId = json.getLongValue("send_uin");
39 | }
40 |
41 | public long getGroupId() {
42 | return groupId;
43 | }
44 |
45 | public void setGroupId(long groupId) {
46 | this.groupId = groupId;
47 | }
48 |
49 | public long getTime() {
50 | return time;
51 | }
52 |
53 | public void setTime(long time) {
54 | this.time = time;
55 | }
56 |
57 | public String getContent() {
58 | return content;
59 | }
60 |
61 | public void setContent(String content) {
62 | this.content = content;
63 | }
64 |
65 | public long getUserId() {
66 | return userId;
67 | }
68 |
69 | public void setUserId(long userId) {
70 | this.userId = userId;
71 | }
72 |
73 | public Font getFont() {
74 | return font;
75 | }
76 |
77 | public void setFont(Font font) {
78 | this.font = font;
79 | }
80 |
81 | @Override
82 | public String toString() {
83 | return "GroupMessage{" +
84 | "groupId=" + groupId +
85 | ", time=" + time +
86 | ", content='" + content + '\'' +
87 | ", userId=" + userId +
88 | ", font=" + font +
89 | '}';
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/weather/client/WeatherInfoClient.java:
--------------------------------------------------------------------------------
1 | package top.itning.weather.client;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 | import net.dongliu.requests.Client;
5 | import net.dongliu.requests.Session;
6 | import top.itning.weather.entity.Weather;
7 | import top.itning.weather.entity.WeatherData;
8 | import top.itning.weather.entity.WeatherInfo;
9 |
10 | import java.text.SimpleDateFormat;
11 | import java.util.Date;
12 | import java.util.Locale;
13 |
14 | /***
15 | *天气信息客户端
16 | * @author : ning
17 | * @version : 1.0.0
18 | * @date : 2017/11/7
19 | **/
20 | public class WeatherInfoClient {
21 | private WeatherInfoClient() {
22 | }
23 |
24 | private static final int SUCCESS_CODE = 200;
25 | private static final String URL = "http://www.sojson.com/open/api/weather/json.shtml?city=宾县";
26 |
27 | /***
28 | * 获取天气信息
29 | * @author : ning
30 | * @return Weather Bean--top.itning.weather.entity.Weather
31 | * @date : 2017/11/7
32 | **/
33 | private static Weather getWeatherInfo() {
34 | Client build = Client.pooled().maxPerRoute(5).maxTotal(10).build();
35 | Session session = build.session();
36 | String body = session.get(URL).text().getBody();
37 | JSONObject jsonObject = JSONObject.parseObject(body);
38 | return JSONObject.toJavaObject(jsonObject, Weather.class);
39 | }
40 |
41 | /***
42 | * 获取格式化后的天气信息
43 | * @author : ning
44 | * @return 格式化后的天气信息--java.lang.String
45 | * @date : 2017/11/7
46 | **/
47 | public static String getFormatWeatherInfo() {
48 | Weather weatherInfo = getWeatherInfo();
49 | if (SUCCESS_CODE == weatherInfo.getStatus()) {
50 | WeatherData data = weatherInfo.getData();
51 | WeatherInfo info = data.getForecast()[0];
52 | return "今天是" +
53 | new SimpleDateFormat("yyyy年MM月dd日 EE ", Locale.CHINESE).format(new Date()) +
54 | "\n" + weatherInfo.getCity() + "天气:\n湿度:" + data.getShidu() +
55 | "\nPM2.5:" + data.getPm25() + "\n可吸入颗粒物:" + data.getPm10() + "\n" +
56 | data.getQuality() + " " + data.getGanmao() +
57 | "\n日出:" + info.getSunrise() + "\t日落:" + info.getSunset() + "\n" + info.getLow() + " " + info.getHigh() + "\n" +
58 | info.getType() + " " + info.getFx() + " " + info.getFl();
59 | }
60 | return null;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/weather/entity/WeatherInfo.java:
--------------------------------------------------------------------------------
1 | package top.itning.weather.entity;
2 |
3 | /**
4 | * @author wangn
5 | */
6 | public class WeatherInfo {
7 | private String date;
8 | private String sunrise;
9 | private String high;
10 | private String low;
11 | private String sunset;
12 | private String aqi;
13 | private String fx;
14 | private String fl;
15 | private String type;
16 |
17 | public String getDate() {
18 | return date;
19 | }
20 |
21 | public void setDate(String date) {
22 | this.date = date;
23 | }
24 |
25 | public String getSunrise() {
26 | return sunrise;
27 | }
28 |
29 | public void setSunrise(String sunrise) {
30 | this.sunrise = sunrise;
31 | }
32 |
33 | public String getHigh() {
34 | return high;
35 | }
36 |
37 | public void setHigh(String high) {
38 | this.high = high;
39 | }
40 |
41 | public String getLow() {
42 | return low;
43 | }
44 |
45 | public void setLow(String low) {
46 | this.low = low;
47 | }
48 |
49 | public String getSunset() {
50 | return sunset;
51 | }
52 |
53 | public void setSunset(String sunset) {
54 | this.sunset = sunset;
55 | }
56 |
57 | public String getAqi() {
58 | return aqi;
59 | }
60 |
61 | public void setAqi(String aqi) {
62 | this.aqi = aqi;
63 | }
64 |
65 | public String getFx() {
66 | return fx;
67 | }
68 |
69 | public void setFx(String fx) {
70 | this.fx = fx;
71 | }
72 |
73 | public String getFl() {
74 | return fl;
75 | }
76 |
77 | public void setFl(String fl) {
78 | this.fl = fl;
79 | }
80 |
81 | public String getType() {
82 | return type;
83 | }
84 |
85 | public void setType(String type) {
86 | this.type = type;
87 | }
88 |
89 | @Override
90 | public String toString() {
91 | return "WeatherInfo{" +
92 | "date='" + date + '\'' +
93 | ", sunrise='" + sunrise + '\'' +
94 | ", high='" + high + '\'' +
95 | ", low='" + low + '\'' +
96 | ", sunset='" + sunset + '\'' +
97 | ", aqi='" + aqi + '\'' +
98 | ", fx='" + fx + '\'' +
99 | ", fl='" + fl + '\'' +
100 | ", type='" + type + '\'' +
101 | '}';
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/webqq/model/GroupUser.java:
--------------------------------------------------------------------------------
1 | package top.itning.webqq.model;
2 |
3 | /**
4 | * 群成员.
5 | *
6 | * @author ScienJus
7 | * @author Liang Ding
8 | * @date 2015/12/24.
9 | */
10 | public class GroupUser {
11 |
12 | private String nick;
13 |
14 | private String province;
15 |
16 | private String gender;
17 |
18 | private long uin;
19 |
20 | private String country;
21 |
22 | private String city;
23 |
24 | private String card;
25 |
26 | private int clientType;
27 |
28 | private int status;
29 |
30 | private boolean vip;
31 |
32 | private int vipLevel;
33 |
34 | public String getNick() {
35 | return nick;
36 | }
37 |
38 | public void setNick(String nick) {
39 | this.nick = nick;
40 | }
41 |
42 | public String getProvince() {
43 | return province;
44 | }
45 |
46 | public void setProvince(String province) {
47 | this.province = province;
48 | }
49 |
50 | public String getGender() {
51 | return gender;
52 | }
53 |
54 | public void setGender(String gender) {
55 | this.gender = gender;
56 | }
57 |
58 | public long getUin() {
59 | return uin;
60 | }
61 |
62 | public void setUin(long uin) {
63 | this.uin = uin;
64 | }
65 |
66 | public String getCountry() {
67 | return country;
68 | }
69 |
70 | public void setCountry(String country) {
71 | this.country = country;
72 | }
73 |
74 | public String getCity() {
75 | return city;
76 | }
77 |
78 | public void setCity(String city) {
79 | this.city = city;
80 | }
81 |
82 | public String getCard() {
83 | return card;
84 | }
85 |
86 | public void setCard(String card) {
87 | this.card = card;
88 | }
89 |
90 | public int getClientType() {
91 | return clientType;
92 | }
93 |
94 | public void setClientType(int clientType) {
95 | this.clientType = clientType;
96 | }
97 |
98 | public int getStatus() {
99 | return status;
100 | }
101 |
102 | public void setStatus(int status) {
103 | this.status = status;
104 | }
105 |
106 | public boolean isVip() {
107 | return vip;
108 | }
109 |
110 | public void setVip(boolean vip) {
111 | this.vip = vip;
112 | }
113 |
114 | public int getVipLevel() {
115 | return vipLevel;
116 | }
117 |
118 | public void setVipLevel(int vipLevel) {
119 | this.vipLevel = vipLevel;
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/Application.java:
--------------------------------------------------------------------------------
1 | package top.itning;
2 |
3 |
4 | import org.apache.log4j.Logger;
5 | import top.itning.timer.TimerTasks;
6 | import top.itning.util.PropertiesUtil;
7 | import top.itning.webqq.callback.MessageCallback;
8 | import top.itning.webqq.client.SmartQQClient;
9 | import top.itning.webqq.model.*;
10 |
11 | import java.io.IOException;
12 | import java.util.List;
13 |
14 |
15 | /**
16 | * 主入口
17 | *
18 | * @author wangn
19 | */
20 | public class Application {
21 |
22 | private static final Logger LOGGER = Logger.getLogger(Application.class);
23 |
24 | private static long User_ID = 0;
25 |
26 | /**
27 | * 程序关闭命令
28 | */
29 | private static final String CLOSE_COMMAND = PropertiesUtil.getValueByKey("close_command", "configurationInfo.properties");
30 |
31 | /**
32 | * 创建一个新对象时需要扫描二维码登录,并且传一个处理接收到消息的回调,如果你不需要接收消息,可以传null
33 | */
34 | private static SmartQQClient client = new SmartQQClient(new MessageCallback() {
35 | @Override
36 | public void onMessage(Message message) {
37 | if (User_ID == message.getUserId()) {
38 | if (CLOSE_COMMAND.equals(message.getContent())) {
39 | client.sendMessageToFriend(User_ID, "关闭成功");
40 | close();
41 | } else {
42 | client.sendMessageToFriend(User_ID, message.getContent());
43 | }
44 |
45 | }
46 | }
47 |
48 | @Override
49 | public void onGroupMessage(GroupMessage message) {
50 |
51 | }
52 |
53 | @Override
54 | public void onDiscussMessage(DiscussMessage message) {
55 |
56 | }
57 | });
58 |
59 | public static void main(String[] args) throws IOException, InterruptedException {
60 | String adminName = PropertiesUtil.getValueByKey("adminName", "configurationInfo.properties");
61 | List friendListWithCategory = client.getFriendListWithCategory();
62 | for (Category c : friendListWithCategory) {
63 | List friends = c.getFriends();
64 | for (Friend friend : friends) {
65 | if (adminName.equals(friend.getNickname()) && friend.getUserId() != 1837634447) {
66 | User_ID = friend.getUserId();
67 | }
68 | }
69 | }
70 | if (User_ID == 0) {
71 | throw new RuntimeException("user id = 0");
72 | }
73 | LOGGER.debug("已获取到User_ID-->" + User_ID);
74 | client.sendMessageToFriend(User_ID, "已获取到User_ID-->" + User_ID);
75 | client.sendMessageToFriend(User_ID, "正在开启...");
76 | new TimerTasks(client);
77 | client.sendMessageToFriend(User_ID, "开启成功!");
78 | }
79 |
80 | /***
81 | * 程序关闭
82 | * @author : ning
83 | * @date : 2017/11/7
84 | **/
85 | private static void close() {
86 | try {
87 | client.close();
88 | System.exit(1);
89 | } catch (IOException e) {
90 | e.printStackTrace();
91 | }
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/timer/TimerTasks.java:
--------------------------------------------------------------------------------
1 | package top.itning.timer;
2 |
3 | import net.dongliu.requests.exception.RequestException;
4 | import org.apache.log4j.Logger;
5 | import top.itning.curriculum.CurriculumClient;
6 | import top.itning.util.PropertiesUtil;
7 | import top.itning.weather.client.WeatherInfoClient;
8 | import top.itning.webqq.client.SmartQQClient;
9 | import top.itning.webqq.model.Group;
10 |
11 | import java.util.*;
12 |
13 | /***
14 | * 定时器任务类
15 | * @author : ning
16 | * @version : 1.0.0
17 | * @date : 2017/11/7
18 | **/
19 | public class TimerTasks {
20 | private static final Logger LOGGER = Logger.getLogger(TimerTasks.class);
21 | /**
22 | * 程序应输入的参数 数
23 | */
24 | private static final int ARGS_LENGTH = 3;
25 |
26 | private SmartQQClient client;
27 | /**
28 | * 重复周期;单位ms
29 | * 24 * 60 * 60 * 1000
30 | */
31 | private static final long PERIOD_DAY = Long.parseLong(PropertiesUtil.getValueByKey("time_period", "configurationInfo.properties") == null ? "8640000" : PropertiesUtil.getValueByKey("time_period", "configurationInfo.properties"));
32 |
33 | /***
34 | * 任务线程
35 | * @author : ning
36 | * @version : 1.0.0
37 | * @date : 2017/11/7
38 | **/
39 | class Task extends TimerTask {
40 |
41 | @Override
42 | public void run() {
43 | // 每次登陆后ID会变 所以动态获取ID
44 | long groupId = 0;
45 | List groupList = client.getGroupList();
46 | for (Group group : groupList) {
47 | if (PropertiesUtil.getValueByKey("groupName", "configurationInfo.properties").equals(group.getName())) {
48 | groupId = group.getId();
49 | }
50 | }
51 | LOGGER.debug("已获取群ID-->" + groupId);
52 | if (groupId == 0) {
53 | throw new RuntimeException("group id = 0");
54 | }
55 | String msg;
56 | if ((msg = WeatherInfoClient.getFormatWeatherInfo()) != null) {
57 | try {
58 | client.sendMessageToGroup(groupId, msg);
59 | } catch (RequestException e) {
60 | System.out.println("java.net.SocketException: Socket Closed");
61 | }
62 |
63 | }
64 | String classInfo = CurriculumClient.getClassInfo();
65 | if (!"".equals(classInfo)) {
66 | try {
67 | client.sendMessageToGroup(groupId, classInfo);
68 | } catch (RequestException e) {
69 | System.out.println("java.net.SocketException: Socket Closed");
70 | }
71 | }
72 | }
73 | }
74 |
75 | /**
76 | * 构造方法
77 | *
78 | * @param client SmartQQClient实例
79 | * @author : ning
80 | **/
81 | public TimerTasks(SmartQQClient client) {
82 | this.client = client;
83 | String[] runTimes = PropertiesUtil.getValueByKey("run_time", "configurationInfo.properties").split(":");
84 | if (runTimes.length != ARGS_LENGTH) {
85 | LOGGER.error("runTimes.length != 3-->" + runTimes.length);
86 | System.exit(0);
87 | }
88 | Calendar calendar = Calendar.getInstance();
89 | calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(runTimes[0]));
90 | calendar.set(Calendar.MINUTE, Integer.parseInt(runTimes[1]));
91 | calendar.set(Calendar.SECOND, Integer.parseInt(runTimes[2]));
92 | //第一次执行定时任务的时间
93 | Date date = calendar.getTime();
94 | //如果第一次执行定时任务的时间 小于当前的时间
95 | //此时要在 第一次执行定时任务的时间加一天,以便此任务在下个时间点执行。如果不加一天,任务会立即执行。
96 | if (date.before(new Date())) {
97 | date = this.addDay(date);
98 | }
99 | Timer timer = new Timer();
100 | Task task = new Task();
101 | //安排指定的任务在指定的时间开始进行重复的固定延迟执行。
102 | timer.schedule(task, date, PERIOD_DAY);
103 | }
104 |
105 | /***
106 | * 增加日期
107 | * @author : ning
108 | * @param date Date实例
109 | * @return Date实例--java.util.Date
110 | * @date : 2017/11/7
111 | **/
112 | private Date addDay(Date date) {
113 | LOGGER.debug("已增加日期");
114 | Calendar startDT = Calendar.getInstance();
115 | startDT.setTime(date);
116 | startDT.add(Calendar.DAY_OF_MONTH, 1);
117 | return startDT.getTime();
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/webqq/model/UserInfo.java:
--------------------------------------------------------------------------------
1 | package top.itning.webqq.model;
2 |
3 | import com.alibaba.fastjson.annotation.JSONField;
4 |
5 | /**
6 | * 用户.
7 | *
8 | * @author ScienJus
9 | * @author Liang Ding
10 | * @date 2015/12/24.
11 | */
12 | public class UserInfo {
13 |
14 | private Birthday birthday;
15 |
16 | private String phone;
17 |
18 | private String occupation;
19 |
20 | private String college;
21 |
22 | private String uin;
23 |
24 | private int blood;
25 |
26 | private String lnick; //签名
27 |
28 | private String homepage;
29 |
30 | @JSONField(name = "vip_info")
31 | private int vipInfo;
32 |
33 | private String city;
34 |
35 | private String country;
36 |
37 | private String province;
38 |
39 | private String personal;
40 |
41 | private int shengxiao;
42 |
43 | private String nick;
44 |
45 | private String email;
46 |
47 | private String account;
48 |
49 | private String gender;
50 |
51 | private String mobile;
52 |
53 | public Birthday getBirthday() {
54 | return birthday;
55 | }
56 |
57 | public void setBirthday(Birthday birthday) {
58 | this.birthday = birthday;
59 | }
60 |
61 | public String getPhone() {
62 | return phone;
63 | }
64 |
65 | public void setPhone(String phone) {
66 | this.phone = phone;
67 | }
68 |
69 | public String getOccupation() {
70 | return occupation;
71 | }
72 |
73 | public void setOccupation(String occupation) {
74 | this.occupation = occupation;
75 | }
76 |
77 | public String getCollege() {
78 | return college;
79 | }
80 |
81 | public void setCollege(String college) {
82 | this.college = college;
83 | }
84 |
85 | public String getUin() {
86 | return uin;
87 | }
88 |
89 | public void setUin(String uin) {
90 | this.uin = uin;
91 | }
92 |
93 | public int getBlood() {
94 | return blood;
95 | }
96 |
97 | public void setBlood(int blood) {
98 | this.blood = blood;
99 | }
100 |
101 | public String getLnick() {
102 | return lnick;
103 | }
104 |
105 | public void setLnick(String lnick) {
106 | this.lnick = lnick;
107 | }
108 |
109 | public String getHomepage() {
110 | return homepage;
111 | }
112 |
113 | public void setHomepage(String homepage) {
114 | this.homepage = homepage;
115 | }
116 |
117 | public int getVipInfo() {
118 | return vipInfo;
119 | }
120 |
121 | public void setVipInfo(int vipInfo) {
122 | this.vipInfo = vipInfo;
123 | }
124 |
125 | public String getCity() {
126 | return city;
127 | }
128 |
129 | public void setCity(String city) {
130 | this.city = city;
131 | }
132 |
133 | public String getCountry() {
134 | return country;
135 | }
136 |
137 | public void setCountry(String country) {
138 | this.country = country;
139 | }
140 |
141 | public String getProvince() {
142 | return province;
143 | }
144 |
145 | public void setProvince(String province) {
146 | this.province = province;
147 | }
148 |
149 | public String getPersonal() {
150 | return personal;
151 | }
152 |
153 | public void setPersonal(String personal) {
154 | this.personal = personal;
155 | }
156 |
157 | public int getShengxiao() {
158 | return shengxiao;
159 | }
160 |
161 | public void setShengxiao(int shengxiao) {
162 | this.shengxiao = shengxiao;
163 | }
164 |
165 | public String getNick() {
166 | return nick;
167 | }
168 |
169 | public void setNick(String nick) {
170 | this.nick = nick;
171 | }
172 |
173 | public String getEmail() {
174 | return email;
175 | }
176 |
177 | public void setEmail(String email) {
178 | this.email = email;
179 | }
180 |
181 | public String getAccount() {
182 | return account;
183 | }
184 |
185 | public void setAccount(String account) {
186 | this.account = account;
187 | }
188 |
189 | public String getGender() {
190 | return gender;
191 | }
192 |
193 | public void setGender(String gender) {
194 | this.gender = gender;
195 | }
196 |
197 | public String getMobile() {
198 | return mobile;
199 | }
200 |
201 | public void setMobile(String mobile) {
202 | this.mobile = mobile;
203 | }
204 |
205 | }
206 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/webqq/constant/ApiURL.java:
--------------------------------------------------------------------------------
1 | package top.itning.webqq.constant;
2 |
3 | /**
4 | * Api的请求地址和Referer
5 | *
6 | * @author ScienJus
7 | * @date 2015/12/19
8 | */
9 | public enum ApiURL {
10 | /**
11 | *
12 | */
13 | GET_QR_CODE(
14 | "https://ssl.ptlogin2.qq.com/ptqrshow?appid=501004106&e=0&l=M&s=5&d=72&v=4&t=0.1",
15 | ""
16 | ),
17 | VERIFY_QR_CODE(
18 | "https://ssl.ptlogin2.qq.com/ptqrlogin?" +
19 | "ptqrtoken={1}&webqq_type=10&remember_uin=1&login2qq=1&aid=501004106&" +
20 | "u1=http%3A%2F%2Fw.qq.com%2Fproxy.html%3Flogin2qq%3D1%26webqq_type%3D10&" +
21 | "ptredirect=0&ptlang=2052&daid=164&from_ui=1&pttype=1&dumy=&fp=loginerroralert&0-0-157510&" +
22 | "mibao_css=m_webqq&t=undefined&g=1&js_type=0&js_ver=10184&login_sig=&pt_randsalt=3",
23 | "https://ui.ptlogin2.qq.com/cgi-bin/login?" +
24 | "daid=164&target=self&style=16&mibao_css=m_webqq&appid=501004106&enable_qlogin=0&no_verifyimg=1&" +
25 | "s_url=http%3A%2F%2Fw.qq.com%2Fproxy.html&f_url=loginerroralert&strong_login=1&login_state=10&t=20131024001"
26 | ),
27 | GET_PTWEBQQ(
28 | "{1}",
29 | null
30 | ),
31 | GET_VFWEBQQ(
32 | "http://s.web2.qq.com/api/getvfwebqq?ptwebqq={1}&clientid=53999199&psessionid=&t=0.1",
33 | "http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1"
34 | ),
35 | GET_UIN_AND_PSESSIONID(
36 | "http://d1.web2.qq.com/channel/login2",
37 | "http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2"
38 | ),
39 | GET_GROUP_LIST(
40 | "http://s.web2.qq.com/api/get_group_name_list_mask2",
41 | "http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2"
42 | ),
43 | POLL_MESSAGE(
44 | "http://d1.web2.qq.com/channel/poll2",
45 | "http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2"
46 | ),
47 | SEND_MESSAGE_TO_GROUP(
48 | "http://d1.web2.qq.com/channel/send_qun_msg2",
49 | "http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2"
50 | ),
51 | GET_FRIEND_LIST(
52 | "http://s.web2.qq.com/api/get_user_friends2",
53 | "http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1"
54 | ),
55 | SEND_MESSAGE_TO_FRIEND(
56 | "http://d1.web2.qq.com/channel/send_buddy_msg2",
57 | "http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2"
58 | ),
59 | GET_DISCUSS_LIST(
60 | "http://s.web2.qq.com/api/get_discus_list?clientid=53999199&psessionid={1}&vfwebqq={2}&t=0.1",
61 | "http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1"
62 | ),
63 | SEND_MESSAGE_TO_DISCUSS(
64 | "http://d1.web2.qq.com/channel/send_discu_msg2",
65 | "http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2"
66 | ),
67 | GET_ACCOUNT_INFO(
68 | "http://s.web2.qq.com/api/get_self_info2?t=0.1",
69 | "http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1"
70 | ),
71 | GET_RECENT_LIST(
72 | "http://d1.web2.qq.com/channel/get_recent_list2",
73 | "http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2"
74 | ),
75 | GET_FRIEND_STATUS(
76 | "http://d1.web2.qq.com/channel/get_online_buddies2?vfwebqq={1}&clientid=53999199&psessionid={2}&t=0.1",
77 | "http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2"
78 | ),
79 | GET_GROUP_INFO(
80 | "http://s.web2.qq.com/api/get_group_info_ext2?gcode={1}&vfwebqq={2}&t=0.1",
81 | "http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1"
82 | ),
83 | GET_QQ_BY_ID(
84 | "http://s.web2.qq.com/api/get_friend_uin2?tuin={1}&type=1&vfwebqq={2}&t=0.1",
85 | "http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1"
86 | ),
87 | GET_DISCUSS_INFO(
88 | "http://d1.web2.qq.com/channel/get_discu_info?did={1}&vfwebqq={2}&clientid=53999199&psessionid={3}&t=0.1",
89 | "http://d1.web2.qq.com/proxy.html?v=20151105001&callback=1&id=2"
90 | ),
91 | GET_FRIEND_INFO(
92 | "http://s.web2.qq.com/api/get_friend_info2?tuin={1}&vfwebqq={2}&clientid=53999199&psessionid={3}&t=0.1",
93 | "http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1"
94 | );
95 |
96 | public static final String USER_AGENT = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36";
97 |
98 | private String url;
99 |
100 | private String referer;
101 |
102 | ApiURL(String url, String referer) {
103 | this.url = url;
104 | this.referer = referer;
105 | }
106 |
107 | public String getUrl() {
108 | return url;
109 | }
110 |
111 |
112 | public String getReferer() {
113 | return referer;
114 | }
115 |
116 | public String buildUrl(Object... params) {
117 | int i = 1;
118 | String url = this.url;
119 | for (Object param : params) {
120 | url = url.replace("{" + i++ + "}", param.toString());
121 | }
122 | return url;
123 | }
124 |
125 | public String getOrigin() {
126 | return this.url.substring(0, url.lastIndexOf("/"));
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/test/java/Test.java:
--------------------------------------------------------------------------------
1 | import com.alibaba.fastjson.JSONObject;
2 | import com.google.common.util.concurrent.ThreadFactoryBuilder;
3 | import top.itning.curriculum.CurriculumClient;
4 | import top.itning.util.PropertiesUtil;
5 | import top.itning.weather.entity.Weather;
6 | import top.itning.weather.entity.WeatherData;
7 | import top.itning.weather.entity.WeatherInfo;
8 |
9 | import java.text.SimpleDateFormat;
10 | import java.util.Calendar;
11 | import java.util.Date;
12 | import java.util.Locale;
13 | import java.util.concurrent.ScheduledThreadPoolExecutor;
14 | import java.util.concurrent.ThreadFactory;
15 | import java.util.concurrent.TimeUnit;
16 |
17 |
18 | public class Test {
19 | private static final String URL = "http://www.sojson.com/open/api/weather/json.shtml?city=宾县";
20 | private static final String DATA = "{\"date\":\"20171106\",\"message\":\"Success !\",\"status\":200,\"city\":\"宾县\",\"count\":2,\"data\":{\"shidu\":\"51%\",\"pm25\":146.0,\"pm10\":154.0,\"quality\":\"中度污染\",\"wendu\":\"11\",\"ganmao\":\"儿童、老年人及心脏、呼吸系统疾病患者人群应减少长时间或高强度户外锻炼,一般人群适量减少户外运动\",\"yesterday\":{\"date\":\"05日星期日\",\"sunrise\":\"06:14\",\"high\":\"高温 10.0℃\",\"low\":\"低温 3.0℃\",\"sunset\":\"16:13\",\"aqi\":126.0,\"fx\":\"西南风\",\"fl\":\"4-5级\",\"type\":\"晴\",\"notice\":\"天气干燥,请适当增加室内湿度\"},\"forecast\":[{\"date\":\"06日星期一\",\"sunrise\":\"06:15\",\"high\":\"高温 12.0℃\",\"low\":\"低温 0.0℃\",\"sunset\":\"16:11\",\"aqi\":139.0,\"fx\":\"西南风\",\"fl\":\"3-4级\",\"type\":\"多云\",\"notice\":\"今日多云,骑上单车去看看世界吧\"},{\"date\":\"07日星期二\",\"sunrise\":\"06:17\",\"high\":\"高温 6.0℃\",\"low\":\"低温 -4.0℃\",\"sunset\":\"16:10\",\"aqi\":158.0,\"fx\":\"北风\",\"fl\":\"3-4级\",\"type\":\"阵雨\",\"notice\":\"愿雨后清新的空气给您带来好心情!\"},{\"date\":\"08日星期三\",\"sunrise\":\"06:18\",\"high\":\"高温 4.0℃\",\"low\":\"低温 -5.0℃\",\"sunset\":\"16:09\",\"aqi\":109.0,\"fx\":\"西风\",\"fl\":\"3-4级\",\"type\":\"多云\",\"notice\":\"今日多云,骑上单车去看看世界吧\"},{\"date\":\"09日星期四\",\"sunrise\":\"06:19\",\"high\":\"高温 6.0℃\",\"low\":\"低温 -4.0℃\",\"sunset\":\"16:07\",\"aqi\":122.0,\"fx\":\"西南风\",\"fl\":\"3-4级\",\"type\":\"多云\",\"notice\":\"绵绵的云朵,形状千变万化\"},{\"date\":\"10日星期五\",\"sunrise\":\"06:21\",\"high\":\"高温 0.0℃\",\"low\":\"低温 -10.0℃\",\"sunset\":\"16:06\",\"aqi\":90.0,\"fx\":\"西风\",\"fl\":\"3-4级\",\"type\":\"阵雪\",\"notice\":\"出现降雪的区域,会给出行带来不便\"}]}}";
21 |
22 | @org.junit.Test
23 | public void test() {
24 | /* Client build = Client.pooled().maxPerRoute(5).maxTotal(10).build();
25 | Session session = build.session();
26 | String body = session.get(URL).text().getBody();
27 | JSONObject jsonObject=JSONObject.parseObject(body);
28 | Weather weather = JSONObject.toJavaObject(jsonObject, Weather.class);
29 | System.out.println(weather);*/
30 | JSONObject jsonObject = JSONObject.parseObject(DATA);
31 | Weather weatherInfo = JSONObject.toJavaObject(jsonObject, Weather.class);
32 | if (200 == weatherInfo.getStatus()) {
33 | WeatherData data = weatherInfo.getData();
34 | WeatherInfo info = data.getForecast()[0];
35 | String msg = "今天是" +
36 | new SimpleDateFormat("yyyy年MM月dd日 EE ").format(new Date()) +
37 | "\n" + weatherInfo.getCity() + "天气:\n湿度:" + data.getShidu() +
38 | "\nPM2.5:" + data.getPm25() + "\n可吸入颗粒物:" + data.getPm10() + "\n" +
39 | data.getQuality() + " " + data.getGanmao() +
40 | "\n日出:" + info.getSunrise() + "\t日落:" + info.getSunset() + "\n" + info.getLow() + " " + info.getHigh() + "\n" +
41 | info.getType() + " " + info.getFx() + " " + info.getFl();
42 | System.out.println(msg);
43 | }
44 | }
45 |
46 | @org.junit.Test
47 | public void tests() {
48 | String classInfo = CurriculumClient.getClassInfo();
49 | System.out.println(classInfo.equals(""));
50 | }
51 |
52 | @org.junit.Test
53 | public void testss() {
54 | String ee = new SimpleDateFormat("EE").format(new Date());
55 | System.out.println(ee);
56 | }
57 |
58 | @org.junit.Test
59 | public void testsss() throws InterruptedException {
60 | String classInfo = CurriculumClient.getClassInfo();
61 | System.out.println(classInfo);
62 | /* Calendar calendar = Calendar.getInstance();
63 | for(int i=1;i<8;i++){
64 | calendar.set(Calendar.DAY_OF_WEEK, i);
65 | //第一次执行定时任务的时间
66 | Date date = calendar.getTime();
67 | System.out.println(new SimpleDateFormat("EE", Locale.US).format(date));
68 | }*/
69 | }
70 |
71 | @org.junit.Test
72 | public void testa() throws InterruptedException {
73 | Calendar calendar = Calendar.getInstance();
74 | calendar.set(Calendar.HOUR_OF_DAY, 19);
75 | calendar.set(Calendar.MINUTE, 16);
76 | calendar.set(Calendar.SECOND, 0);
77 | //第一次执行定时任务的时间
78 | Date date = calendar.getTime();
79 | ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build();
80 | ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(2, namedThreadFactory);
81 | scheduledThreadPoolExecutor.scheduleAtFixedRate(() -> {
82 | System.out.println("111");
83 | }, date.getTime(), 500, TimeUnit.MILLISECONDS);
84 | Thread.sleep(99999999);
85 | }
86 |
87 | @org.junit.Test
88 | public void testb() throws InterruptedException {
89 | String adminName = PropertiesUtil.getValueByKey("groupName", "configurationInfo.properties");
90 | System.out.println(adminName);
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/src/main/java/top/itning/webqq/client/SmartQQClient.java:
--------------------------------------------------------------------------------
1 | package top.itning.webqq.client;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.alibaba.fastjson.JSONArray;
5 | import com.alibaba.fastjson.JSONObject;
6 | import com.google.common.util.concurrent.ThreadFactoryBuilder;
7 | import net.dongliu.requests.Client;
8 | import net.dongliu.requests.HeadOnlyRequestBuilder;
9 | import net.dongliu.requests.Response;
10 | import net.dongliu.requests.Session;
11 | import net.dongliu.requests.exception.RequestException;
12 | import net.dongliu.requests.struct.Cookie;
13 | import org.apache.log4j.Logger;
14 | import top.itning.webqq.callback.MessageCallback;
15 | import top.itning.webqq.constant.ApiURL;
16 | import top.itning.webqq.model.*;
17 |
18 | import java.io.Closeable;
19 | import java.io.File;
20 | import java.io.IOException;
21 | import java.net.SocketTimeoutException;
22 | import java.nio.charset.StandardCharsets;
23 | import java.util.*;
24 | import java.util.concurrent.ScheduledThreadPoolExecutor;
25 | import java.util.concurrent.ThreadFactory;
26 | import java.util.concurrent.TimeUnit;
27 |
28 | /***
29 | *
30 | * @author : ning
31 | * @version : 1.0.0
32 | * @date : 2017/11/7
33 | **/
34 | public class SmartQQClient implements Closeable {
35 | /**
36 | * 分隔符
37 | */
38 | private static final String SPLIT_SYMBOL = "','";
39 | /**
40 | * 失败码
41 | */
42 | private static final int NOT_FOUNT_CODE = 404;
43 | /**
44 | * 成功码
45 | */
46 | private static final int SUCCESS_CODE = 200;
47 | /**
48 | * 日志
49 | */
50 | private static final Logger LOGGER = Logger.getLogger(SmartQQClient.class);
51 |
52 | /**
53 | * 发生ngnix 404 时的重试次数
54 | */
55 | private static int retryTimesOnFailed = 3;
56 |
57 | /**
58 | * 消息id,这个好像可以随便设置,所以设成全局的
59 | */
60 | private static long MESSAGE_ID = 43690001;
61 |
62 | /**
63 | * 客户端id,固定的
64 | */
65 | private static final long CLIENT_ID = 53999199;
66 |
67 | /**
68 | * 消息发送失败重发次数
69 | */
70 | private static final long RETRY_TIMES = 5;
71 |
72 | /**
73 | * 客户端
74 | */
75 | private Client client;
76 |
77 | /**
78 | * 会话
79 | */
80 | private Session session;
81 |
82 | /**
83 | * 二维码令牌
84 | */
85 | private String qrsig;
86 |
87 | /**
88 | * 鉴权参数
89 | */
90 | private String ptwebqq;
91 |
92 | private String vfwebqq;
93 | private long uin;
94 | private String psessionid;
95 |
96 | /**
97 | * 线程开关
98 | */
99 | private volatile boolean pollStarted;
100 |
101 |
102 | public SmartQQClient(final MessageCallback callback) {
103 | this.client = Client.pooled().maxPerRoute(5).maxTotal(10).build();
104 | this.session = client.session();
105 | login();
106 | if (callback != null) {
107 | this.pollStarted = true;
108 | ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build();
109 | ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(2, namedThreadFactory);
110 | scheduledThreadPoolExecutor.scheduleAtFixedRate(
111 | () -> {
112 | if (!pollStarted) {
113 | return;
114 | }
115 | try {
116 | pollMessage(callback);
117 | } catch (RequestException e) {
118 | //忽略SocketTimeoutException
119 | if (!(e.getCause() instanceof SocketTimeoutException)) {
120 | LOGGER.error(e.getMessage());
121 | }
122 | } catch (Exception e) {
123 | LOGGER.error(e.getMessage());
124 | }
125 | },
126 | 0, 500, TimeUnit.MILLISECONDS);
127 | }
128 | }
129 |
130 | /**
131 | * 登录
132 | */
133 | private void login() {
134 | getQRCode();
135 | String url = verifyQRCode();
136 | getPtwebqq(url);
137 | getVfwebqq();
138 | getUinAndPsessionid();
139 | getFriendStatus(); //修复Api返回码[103]的问题
140 | //登录成功欢迎语
141 | UserInfo userInfo = getAccountInfo();
142 | LOGGER.info(userInfo.getNick() + ",欢迎!");
143 | }
144 |
145 | /**
146 | * 登录流程1:获取二维码
147 | */
148 | private void getQRCode() {
149 | LOGGER.debug("开始获取二维码");
150 |
151 | //本地存储二维码图片
152 | String filePath;
153 | try {
154 | filePath = new File("qrcode.png").getCanonicalPath();
155 | } catch (IOException e) {
156 | throw new IllegalStateException("二维码保存失败");
157 | }
158 | Response response = session.get(ApiURL.GET_QR_CODE.getUrl())
159 | .addHeader("User-Agent", ApiURL.USER_AGENT)
160 | .file(filePath);
161 | for (Cookie cookie : response.getCookies()) {
162 | if ("qrsig".equals(cookie.getName())) {
163 | qrsig = cookie.getValue();
164 | break;
165 | }
166 | }
167 | LOGGER.info("二维码已保存在 " + filePath + " 文件中,请打开手机QQ并扫描二维码");
168 | }
169 |
170 | /**
171 | * 用于生成ptqrtoken的哈希函数
172 | *
173 | * @param s qrsig
174 | * @return 哈希数
175 | */
176 | private static int hash33(String s) {
177 | int e = 0, n = s.length();
178 | for (int i = 0; n > i; ++i) {
179 | e += (e << 5) + s.charAt(i);
180 | }
181 | return 2147483647 & e;
182 | }
183 |
184 | /**
185 | * 登录流程2:校验二维码
186 | *
187 | * @return url
188 | */
189 | private String verifyQRCode() {
190 | LOGGER.debug("等待扫描二维码");
191 |
192 | //阻塞直到确认二维码认证成功
193 | while (true) {
194 | sleep(1);
195 | Response response = get(ApiURL.VERIFY_QR_CODE, hash33(qrsig));
196 | String result = response.getBody();
197 | if (result.contains("成功")) {
198 | for (String content : result.split(SPLIT_SYMBOL)) {
199 | if (content.startsWith("http")) {
200 | LOGGER.info("正在登录,请稍后");
201 | return content;
202 | }
203 | }
204 | } else if (result.contains("已失效")) {
205 | LOGGER.info("二维码已失效,尝试重新获取二维码");
206 | getQRCode();
207 | }
208 | }
209 |
210 | }
211 |
212 | /**
213 | * 登录流程3:获取ptwebqq
214 | *
215 | * @param url url
216 | */
217 | private void getPtwebqq(String url) {
218 | LOGGER.debug("开始获取ptwebqq");
219 |
220 | Response response = get(ApiURL.GET_PTWEBQQ, url);
221 | this.ptwebqq = response.getCookies().get("ptwebqq").iterator().next().getValue();
222 | }
223 |
224 | /**
225 | * 登录流程4:获取vfwebqq
226 | */
227 | private void getVfwebqq() {
228 | LOGGER.debug("开始获取vfwebqq");
229 |
230 | Response response = get(ApiURL.GET_VFWEBQQ, ptwebqq);
231 | int retryTimes4Vfwebqq = retryTimesOnFailed;
232 | while (response.getStatusCode() == NOT_FOUNT_CODE && retryTimes4Vfwebqq > 0) {
233 | response = get(ApiURL.GET_VFWEBQQ, ptwebqq);
234 | retryTimes4Vfwebqq--;
235 | }
236 | this.vfwebqq = getJsonObjectResult(response).getString("vfwebqq");
237 | }
238 |
239 | /**
240 | * 登录流程5:获取uin和psessionid
241 | */
242 | private void getUinAndPsessionid() {
243 | LOGGER.debug("开始获取uin和psessionid");
244 |
245 | JSONObject r = new JSONObject();
246 | r.put("ptwebqq", ptwebqq);
247 | r.put("clientid", CLIENT_ID);
248 | r.put("psessionid", "");
249 | r.put("status", "online");
250 |
251 | Response response = post(ApiURL.GET_UIN_AND_PSESSIONID, r);
252 | JSONObject result = getJsonObjectResult(response);
253 | this.psessionid = result.getString("psessionid");
254 | this.uin = result.getLongValue("uin");
255 | }
256 |
257 | /**
258 | * 获取群列表
259 | *
260 | * @return 群列表
261 | */
262 | public List getGroupList() {
263 | LOGGER.debug("开始获取群列表");
264 |
265 | JSONObject r = new JSONObject();
266 | r.put("vfwebqq", vfwebqq);
267 | r.put("hash", hash());
268 |
269 | Response response = post(ApiURL.GET_GROUP_LIST, r);
270 | int retryTimes4getGroupList = retryTimesOnFailed;
271 | while (response.getStatusCode() == NOT_FOUNT_CODE && retryTimes4getGroupList > 0) {
272 | response = post(ApiURL.GET_GROUP_LIST, r);
273 | retryTimes4getGroupList--;
274 | }
275 | JSONObject result = getJsonObjectResult(response);
276 | return JSON.parseArray(result.getJSONArray("gnamelist").toJSONString(), Group.class);
277 | }
278 |
279 | /**
280 | * 拉取消息
281 | *
282 | * @param callback 获取消息后的回调
283 | */
284 | private void pollMessage(MessageCallback callback) {
285 | LOGGER.debug("开始接收消息");
286 |
287 | JSONObject r = new JSONObject();
288 | r.put("ptwebqq", ptwebqq);
289 | r.put("clientid", CLIENT_ID);
290 | r.put("psessionid", psessionid);
291 | r.put("key", "");
292 |
293 | Response response = post(ApiURL.POLL_MESSAGE, r);
294 | JSONArray array = getJsonArrayResult(response);
295 | for (int i = 0; array != null && i < array.size(); i++) {
296 | JSONObject message = array.getJSONObject(i);
297 | String type = message.getString("poll_type");
298 | if ("message".equals(type)) {
299 | callback.onMessage(new Message(message.getJSONObject("value")));
300 | } else if ("group_message".equals(type)) {
301 | callback.onGroupMessage(new GroupMessage(message.getJSONObject("value")));
302 | } else if ("discu_message".equals(type)) {
303 | callback.onDiscussMessage(new DiscussMessage(message.getJSONObject("value")));
304 | }
305 | }
306 | }
307 |
308 | /**
309 | * 发送群消息
310 | *
311 | * @param groupId 群id
312 | * @param msg 消息内容
313 | */
314 | public void sendMessageToGroup(long groupId, String msg) {
315 | LOGGER.debug("开始发送群消息");
316 |
317 | JSONObject r = new JSONObject();
318 | r.put("group_uin", groupId);
319 | //注意这里虽然格式是Json,但是实际是String
320 | r.put("content", JSON.toJSONString(Arrays.asList(msg, Arrays.asList("font", Font.DEFAULT_FONT))));
321 | r.put("face", 573);
322 | r.put("clientid", CLIENT_ID);
323 | r.put("msg_id", MESSAGE_ID++);
324 | r.put("psessionid", psessionid);
325 |
326 | Response response = postWithRetry(ApiURL.SEND_MESSAGE_TO_GROUP, r);
327 | checkSendMsgResult(response);
328 | }
329 |
330 | /**
331 | * 发送讨论组消息
332 | *
333 | * @param discussId 讨论组id
334 | * @param msg 消息内容
335 | */
336 | public void sendMessageToDiscuss(long discussId, String msg) {
337 | LOGGER.debug("开始发送讨论组消息");
338 |
339 | JSONObject r = new JSONObject();
340 | r.put("did", discussId);
341 | //注意这里虽然格式是Json,但是实际是String
342 | r.put("content", JSON.toJSONString(Arrays.asList(msg, Arrays.asList("font", Font.DEFAULT_FONT))));
343 | r.put("face", 573);
344 | r.put("clientid", CLIENT_ID);
345 | r.put("msg_id", MESSAGE_ID++);
346 | r.put("psessionid", psessionid);
347 |
348 | Response response = postWithRetry(ApiURL.SEND_MESSAGE_TO_DISCUSS, r);
349 | checkSendMsgResult(response);
350 | }
351 |
352 | /**
353 | * 发送消息
354 | *
355 | * @param friendId 好友id
356 | * @param msg 消息内容
357 | */
358 | public void sendMessageToFriend(long friendId, String msg) {
359 | LOGGER.debug("开始发送消息");
360 |
361 | JSONObject r = new JSONObject();
362 | r.put("to", friendId);
363 | //注意这里虽然格式是Json,但是实际是String
364 | r.put("content", JSON.toJSONString(Arrays.asList(msg, Arrays.asList("font", Font.DEFAULT_FONT))));
365 | r.put("face", 573);
366 | r.put("clientid", CLIENT_ID);
367 | r.put("msg_id", MESSAGE_ID++);
368 | r.put("psessionid", psessionid);
369 |
370 | Response response = postWithRetry(ApiURL.SEND_MESSAGE_TO_FRIEND, r);
371 | checkSendMsgResult(response);
372 | }
373 |
374 | /**
375 | * 获得讨论组列表
376 | *
377 | * @return 讨论组列表
378 | */
379 | public List getDiscussList() {
380 | LOGGER.debug("开始获取讨论组列表");
381 |
382 | Response response = get(ApiURL.GET_DISCUSS_LIST, psessionid, vfwebqq);
383 | return JSON.parseArray(getJsonObjectResult(response).getJSONArray("dnamelist").toJSONString(), Discuss.class);
384 | }
385 |
386 | /**
387 | * 获得好友列表(包含分组信息)
388 | *
389 | * @return 好友列表
390 | */
391 | public List getFriendListWithCategory() {
392 | LOGGER.debug("开始获取好友列表");
393 |
394 | JSONObject r = new JSONObject();
395 | r.put("vfwebqq", vfwebqq);
396 | r.put("hash", hash());
397 |
398 | Response response = post(ApiURL.GET_FRIEND_LIST, r);
399 | JSONObject result = getJsonObjectResult(response);
400 | //获得好友信息
401 | Map friendMap = parseFriendMap(result);
402 | //获得分组
403 | JSONArray categories = result.getJSONArray("categories");
404 | Map categoryMap = new HashMap<>(16);
405 | categoryMap.put(0, Category.defaultCategory());
406 | for (int i = 0; categories != null && i < categories.size(); i++) {
407 | Category category = categories.getObject(i, Category.class);
408 | categoryMap.put(category.getIndex(), category);
409 | }
410 | JSONArray friends = result.getJSONArray("friends");
411 | for (int i = 0; friends != null && i < friends.size(); i++) {
412 | JSONObject item = friends.getJSONObject(i);
413 | Friend friend = friendMap.get(item.getLongValue("uin"));
414 | categoryMap.get(item.getIntValue("categories")).addFriend(friend);
415 | }
416 | return new ArrayList<>(categoryMap.values());
417 | }
418 |
419 | /**
420 | * 获取好友列表
421 | *
422 | * @return 好友列表
423 | */
424 | public List getFriendList() {
425 | LOGGER.debug("开始获取好友列表");
426 |
427 | JSONObject r = new JSONObject();
428 | r.put("vfwebqq", vfwebqq);
429 | r.put("hash", hash());
430 |
431 | Response response = post(ApiURL.GET_FRIEND_LIST, r);
432 | return new ArrayList<>(parseFriendMap(getJsonObjectResult(response)).values());
433 | }
434 |
435 | /**
436 | * 将json解析为好友列表
437 | *
438 | * @param result json
439 | * @return 好友列表
440 | */
441 | private static Map parseFriendMap(JSONObject result) {
442 | Map friendMap = new HashMap<>(16);
443 | JSONArray info = result.getJSONArray("info");
444 | for (int i = 0; info != null && i < info.size(); i++) {
445 | JSONObject item = info.getJSONObject(i);
446 | Friend friend = new Friend();
447 | friend.setUserId(item.getLongValue("uin"));
448 | friend.setNickname(item.getString("nick"));
449 | friendMap.put(friend.getUserId(), friend);
450 | }
451 | JSONArray marknames = result.getJSONArray("marknames");
452 | for (int i = 0; marknames != null && i < marknames.size(); i++) {
453 | JSONObject item = marknames.getJSONObject(i);
454 | friendMap.get(item.getLongValue("uin")).setMarkname(item.getString("markname"));
455 | }
456 | JSONArray vipinfo = result.getJSONArray("vipinfo");
457 | for (int i = 0; vipinfo != null && i < vipinfo.size(); i++) {
458 | JSONObject item = vipinfo.getJSONObject(i);
459 | Friend friend = friendMap.get(item.getLongValue("u"));
460 | friend.setVip(item.getIntValue("is_vip") == 1);
461 | friend.setVipLevel(item.getIntValue("vip_level"));
462 | }
463 | return friendMap;
464 | }
465 |
466 | /**
467 | * 获得当前登录用户的详细信息
468 | *
469 | * @return 用户的详细信息
470 | */
471 | public UserInfo getAccountInfo() {
472 | LOGGER.debug("开始获取登录用户信息");
473 |
474 | Response response = get(ApiURL.GET_ACCOUNT_INFO);
475 | int retryTimes4AccountInfo = retryTimesOnFailed;
476 | while (response.getStatusCode() == NOT_FOUNT_CODE && retryTimes4AccountInfo > 0) {
477 | response = get(ApiURL.GET_ACCOUNT_INFO);
478 | retryTimes4AccountInfo--;
479 | }
480 | return JSON.parseObject(getJsonObjectResult(response).toJSONString(), UserInfo.class);
481 | }
482 |
483 | /**
484 | * 获得好友的详细信息
485 | *
486 | * @return 好友的详细信息
487 | */
488 | public UserInfo getFriendInfo(long friendId) {
489 | LOGGER.debug("开始获取好友信息");
490 |
491 | Response response = get(ApiURL.GET_FRIEND_INFO, friendId, vfwebqq, psessionid);
492 | return JSON.parseObject(getJsonObjectResult(response).toJSONString(), UserInfo.class);
493 | }
494 |
495 | /**
496 | * 获得最近会话列表
497 | *
498 | * @return 最近会话列表
499 | */
500 | public List getRecentList() {
501 | LOGGER.debug("开始获取最近会话列表");
502 |
503 | JSONObject r = new JSONObject();
504 | r.put("vfwebqq", vfwebqq);
505 | r.put("clientid", CLIENT_ID);
506 | r.put("psessionid", "");
507 |
508 | Response response = post(ApiURL.GET_RECENT_LIST, r);
509 | return JSON.parseArray(getJsonArrayResult(response).toJSONString(), Recent.class);
510 | }
511 |
512 | /**
513 | * 获得qq号
514 | *
515 | * @param friendId 用户id
516 | * @return qq号
517 | */
518 | public long getQQById(long friendId) {
519 | LOGGER.debug("开始获取QQ号");
520 | Response response = get(ApiURL.GET_QQ_BY_ID, friendId, vfwebqq);
521 | return getJsonObjectResult(response).getLongValue("account");
522 | }
523 |
524 | /**
525 | * 获得好友的qq号
526 | *
527 | * @param friend 好友对象
528 | * @return qq号
529 | */
530 | public long getQQById(Friend friend) {
531 | return getQQById(friend.getUserId());
532 | }
533 |
534 | /**
535 | * 获得群友的qq号
536 | *
537 | * @param user 群友对象
538 | * @return qq号
539 | */
540 | public long getQQById(GroupUser user) {
541 | return getQQById(user.getUin());
542 | }
543 |
544 | /**
545 | * 获得讨论组成员的qq号
546 | *
547 | * @param user 讨论组成员对象
548 | * @return qq号
549 | */
550 | public long getQQById(DiscussUser user) {
551 | return getQQById(user.getUin());
552 | }
553 |
554 | /**
555 | * 获得私聊消息发送者的qq号
556 | *
557 | * @param msg 私聊消息
558 | * @return qq号
559 | */
560 | public long getQQById(Message msg) {
561 | return getQQById(msg.getUserId());
562 | }
563 |
564 | /**
565 | * 获得群消息发送者的qq号
566 | *
567 | * @param msg 群消息
568 | * @return qq号
569 | */
570 | public long getQQById(GroupMessage msg) {
571 | return getQQById(msg.getUserId());
572 | }
573 |
574 | /**
575 | * 获得讨论组消息发送者的qq号
576 | *
577 | * @param msg 讨论组消息
578 | * @return qq号
579 | */
580 | public long getQQById(DiscussMessage msg) {
581 | return getQQById(msg.getUserId());
582 | }
583 |
584 | /**
585 | * 获得登录状态
586 | *
587 | * @return 登录状态
588 | */
589 | public List getFriendStatus() {
590 | LOGGER.debug("开始获取好友状态");
591 | Response response = get(ApiURL.GET_FRIEND_STATUS, vfwebqq, psessionid);
592 | return JSON.parseArray(getJsonArrayResult(response).toJSONString(), FriendStatus.class);
593 | }
594 |
595 | /**
596 | * 获得群的详细信息
597 | *
598 | * @param groupCode 群编号
599 | * @return 详细信息
600 | */
601 | public GroupInfo getGroupInfo(long groupCode) {
602 | LOGGER.debug("开始获取群资料");
603 |
604 | Response response = get(ApiURL.GET_GROUP_INFO, groupCode, vfwebqq);
605 | JSONObject result = getJsonObjectResult(response);
606 | GroupInfo groupInfo = result.getObject("ginfo", GroupInfo.class);
607 | //获得群成员信息
608 | Map groupUserMap = new HashMap<>(16);
609 | JSONArray minfo = result.getJSONArray("minfo");
610 | for (int i = 0; minfo != null && i < minfo.size(); i++) {
611 | GroupUser groupUser = minfo.getObject(i, GroupUser.class);
612 | groupUserMap.put(groupUser.getUin(), groupUser);
613 | groupInfo.addUser(groupUser);
614 | }
615 | JSONArray stats = result.getJSONArray("stats");
616 | for (int i = 0; stats != null && i < stats.size(); i++) {
617 | JSONObject item = stats.getJSONObject(i);
618 | GroupUser groupUser = groupUserMap.get(item.getLongValue("uin"));
619 | groupUser.setClientType(item.getIntValue("client_type"));
620 | groupUser.setStatus(item.getIntValue("stat"));
621 | }
622 | JSONArray cards = result.getJSONArray("cards");
623 | for (int i = 0; cards != null && i < cards.size(); i++) {
624 | JSONObject item = cards.getJSONObject(i);
625 | groupUserMap.get(item.getLongValue("muin")).setCard(item.getString("card"));
626 | }
627 | JSONArray vipinfo = result.getJSONArray("vipinfo");
628 | for (int i = 0; vipinfo != null && i < vipinfo.size(); i++) {
629 | JSONObject item = vipinfo.getJSONObject(i);
630 | GroupUser groupUser = groupUserMap.get(item.getLongValue("u"));
631 | groupUser.setVip(item.getIntValue("is_vip") == 1);
632 | groupUser.setVipLevel(item.getIntValue("vip_level"));
633 | }
634 | return groupInfo;
635 | }
636 |
637 | /**
638 | * 获得讨论组的详细信息
639 | *
640 | * @param discussId 讨论组id
641 | * @return 详细信息
642 | */
643 | public DiscussInfo getDiscussInfo(long discussId) {
644 | LOGGER.debug("开始获取讨论组资料");
645 |
646 | Response response = get(ApiURL.GET_DISCUSS_INFO, discussId, vfwebqq, psessionid);
647 | JSONObject result = getJsonObjectResult(response);
648 | DiscussInfo discussInfo = result.getObject("info", DiscussInfo.class);
649 | //获得讨论组成员信息
650 | Map discussUserMap = new HashMap<>(16);
651 | JSONArray minfo = result.getJSONArray("mem_info");
652 | for (int i = 0; minfo != null && i < minfo.size(); i++) {
653 | DiscussUser discussUser = minfo.getObject(i, DiscussUser.class);
654 | discussUserMap.put(discussUser.getUin(), discussUser);
655 | discussInfo.addUser(discussUser);
656 | }
657 | JSONArray stats = result.getJSONArray("mem_status");
658 | for (int i = 0; stats != null && i < stats.size(); i++) {
659 | JSONObject item = stats.getJSONObject(i);
660 | DiscussUser discussUser = discussUserMap.get(item.getLongValue("uin"));
661 | discussUser.setClientType(item.getIntValue("client_type"));
662 | discussUser.setStatus(item.getString("status"));
663 | }
664 | return discussInfo;
665 | }
666 |
667 | /**
668 | * 发送get请求
669 | *
670 | * @param url url
671 | * @param params 参数
672 | * @return 结果
673 | */
674 | private Response get(ApiURL url, Object... params) {
675 | HeadOnlyRequestBuilder request = session.get(url.buildUrl(params))
676 | .addHeader("User-Agent", ApiURL.USER_AGENT);
677 | if (url.getReferer() != null) {
678 | request.addHeader("Referer", url.getReferer());
679 | }
680 | return request.text(StandardCharsets.UTF_8);
681 | }
682 |
683 | /**
684 | * 发送post请求
685 | *
686 | * @param url url
687 | * @param r JSONObject
688 | * @return Response
689 | */
690 | private Response post(ApiURL url, JSONObject r) {
691 | return session.post(url.getUrl())
692 | .addHeader("User-Agent", ApiURL.USER_AGENT)
693 | .addHeader("Referer", url.getReferer())
694 | .addHeader("Origin", url.getOrigin())
695 | .addForm("r", r.toJSONString())
696 | .text(StandardCharsets.UTF_8);
697 | }
698 |
699 | /**
700 | * 发送post请求,失败时重试
701 | *
702 | * @param url url
703 | * @param r JSONObject
704 | * @return Response
705 | */
706 | private Response postWithRetry(ApiURL url, JSONObject r) {
707 | int times = 0;
708 | Response response;
709 | do {
710 | response = post(url, r);
711 | times++;
712 | } while (times < RETRY_TIMES && response.getStatusCode() != SUCCESS_CODE);
713 | return response;
714 | }
715 |
716 | /**
717 | * 获取返回json的result字段(JSONObject类型)
718 | *
719 | * @param response Response
720 | * @return JSONObject
721 | */
722 | private static JSONObject getJsonObjectResult(Response response) {
723 | return getResponseJson(response).getJSONObject("result");
724 | }
725 |
726 | /**
727 | * 获取返回json的result字段(JSONArray类型)
728 | *
729 | * @param response Response
730 | * @return JSONArray
731 | */
732 | private static JSONArray getJsonArrayResult(Response response) {
733 | return getResponseJson(response).getJSONArray("result");
734 | }
735 |
736 | /**
737 | * 检查消息是否发送成功
738 | *
739 | * @param response Response
740 | */
741 | private static void checkSendMsgResult(Response response) {
742 | if (response.getStatusCode() != SUCCESS_CODE) {
743 | LOGGER.error(String.format("发送失败,Http返回码[%d]", response.getStatusCode()));
744 | }
745 | JSONObject json = JSON.parseObject(response.getBody());
746 | Integer errCode = json.getInteger("retcode");
747 | if (errCode != null && errCode == 0) {
748 | LOGGER.debug("发送成功");
749 | } else {
750 | LOGGER.error(String.format("发送失败,Api返回码[%d]", json.getInteger("retcode")));
751 | }
752 | }
753 |
754 | /**
755 | * 检验Json返回结果
756 | *
757 | * @param response Response
758 | * @return JSONObject
759 | */
760 | private static JSONObject getResponseJson(Response response) {
761 | if (response.getStatusCode() != SUCCESS_CODE) {
762 | throw new RequestException(String.format("请求失败,Http返回码[%d]", response.getStatusCode()));
763 | }
764 | JSONObject json = JSON.parseObject(response.getBody());
765 | Integer retCode = json.getInteger("retcode");
766 | if (retCode == null) {
767 | throw new RequestException("请求失败,Api返回异常 retCode == null");
768 | } else if (retCode != 0) {
769 | switch (retCode) {
770 | case 103: {
771 | LOGGER.error("请求失败,Api返回码[103]。你需要进入http://w.qq.com,检查是否能正常接收消息。如果可以的话点击[设置]->[退出登录]后查看是否恢复正常");
772 | break;
773 | }
774 | case 100100: {
775 | LOGGER.debug("请求失败,Api返回码[100100]");
776 | break;
777 | }
778 | default: {
779 | throw new RequestException(String.format("请求失败,Api返回码[%d]", retCode));
780 | }
781 | }
782 | }
783 | return json;
784 | }
785 |
786 | /**
787 | * hash加密方法
788 | *
789 | * @return hash加密
790 | */
791 | private String hash() {
792 | return hash(uin, ptwebqq);
793 | }
794 |
795 | /**
796 | * 线程暂停
797 | *
798 | * @param seconds 时间
799 | */
800 | private static void sleep(long seconds) {
801 | try {
802 | Thread.sleep(seconds * 1000);
803 | } catch (InterruptedException e) {
804 | //忽略InterruptedException
805 | }
806 | }
807 |
808 | /**
809 | * hash加密方法
810 | *
811 | * @param x x
812 | * @param k k
813 | * @return String
814 | */
815 | private static String hash(long x, String k) {
816 | int[] n = new int[4];
817 | for (int t = 0; t < k.length(); t++) {
818 | n[t % 4] ^= k.charAt(t);
819 | }
820 | String[] u = {"EC", "OK"};
821 | long[] v = new long[4];
822 | v[0] = x >> 24 & 255 ^ u[0].charAt(0);
823 | v[1] = x >> 16 & 255 ^ u[0].charAt(1);
824 | v[2] = x >> 8 & 255 ^ u[1].charAt(0);
825 | v[3] = x & 255 ^ u[1].charAt(1);
826 |
827 | long[] u1 = new long[8];
828 |
829 | for (int t = 0; t < 8; t++) {
830 | u1[t] = t % 2 == 0 ? n[t >> 1] : v[t >> 1];
831 | }
832 |
833 | String[] n1 = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};
834 | StringBuilder v1 = new StringBuilder();
835 | for (long aU1 : u1) {
836 | v1.append(n1[(int) ((aU1 >> 4) & 15)]);
837 | v1.append(n1[(int) (aU1 & 15)]);
838 | }
839 | return v1.toString();
840 | }
841 |
842 | @Override
843 | public void close() throws IOException {
844 | this.pollStarted = false;
845 | if (this.client != null) {
846 | this.client.close();
847 | }
848 | }
849 | }
850 |
--------------------------------------------------------------------------------