Showing preview only (750K chars total). Download the full file or copy to clipboard to get everything.
Repository: scorego/WechatRobot
Branch: master
Commit: 1d75b62566f3
Files: 84
Total size: 683.9 KB
Directory structure:
gitextract_p348k3l_/
├── .gitignore
├── LICENSE.md
├── README.md
├── doc/
│ └── OLD_README.md
├── pom.xml
└── src/
├── main/
│ ├── java/
│ │ ├── IdentifyCommand/
│ │ │ ├── CheckCommandType.java
│ │ │ └── PreProcessMessage.java
│ │ ├── WechatBot.java
│ │ ├── api/
│ │ │ ├── ChatApi.java
│ │ │ ├── EveryDayHelloApi.java
│ │ │ ├── HelpMsg.java
│ │ │ ├── NewsApi.java
│ │ │ ├── RubbishApi.java
│ │ │ ├── WeatherApi.java
│ │ │ ├── ZhihuHotApi.java
│ │ │ └── entity/
│ │ │ └── RubbishToolBoxResponseEntity.java
│ │ ├── cache/
│ │ │ └── redis/
│ │ │ ├── NewsCacheFactory.java
│ │ │ ├── RubbishLinkCacheFactory.java
│ │ │ ├── RubbishTypeCacheFactory.java
│ │ │ ├── WeatherCacheFactory.java
│ │ │ ├── ZhihuHotCacheFactory.java
│ │ │ ├── entity/
│ │ │ │ ├── NewsCacheEntity.java
│ │ │ │ ├── RubbishCacheEntity.java
│ │ │ │ ├── RubbishLinkCacheEntity.java
│ │ │ │ ├── WeatherCacheEntity.java
│ │ │ │ └── ZhihuHotCacheEntity.java
│ │ │ └── provider/
│ │ │ ├── BaseRedisCache.java
│ │ │ ├── JedisPoolUtil.java
│ │ │ └── RCacheEntity.java
│ │ ├── config/
│ │ │ ├── GlobalConfig.java
│ │ │ ├── QingWeatherCityConfig.java
│ │ │ └── RedisConfig.java
│ │ ├── cons/
│ │ │ └── WxMsg.java
│ │ ├── enums/
│ │ │ ├── CommandType.java
│ │ │ ├── FriendType.java
│ │ │ ├── GroupType.java
│ │ │ └── RubbishType.java
│ │ ├── main/
│ │ │ ├── WechatBotClient.java
│ │ │ ├── facade/
│ │ │ │ ├── DealMessage.java
│ │ │ │ └── DoCommand.java
│ │ │ └── service/
│ │ │ ├── everydayHelloMsg/
│ │ │ │ └── EveryDayHelloWhiteList.java
│ │ │ ├── friendMsg/
│ │ │ │ ├── CheckFriendType.java
│ │ │ │ └── FriendChat.java
│ │ │ └── groupMsg/
│ │ │ ├── CheckGroupType.java
│ │ │ ├── GroupChat.java
│ │ │ └── GroupTextCommand.java
│ │ ├── robot/
│ │ │ ├── AToolBox/
│ │ │ │ ├── ToolBoxRubbish.java
│ │ │ │ └── entity/
│ │ │ │ └── ToolBoxRubbishContentEntity.java
│ │ │ ├── Ciba/
│ │ │ │ ├── CibaEveryDayHello.java
│ │ │ │ └── entity/
│ │ │ │ └── CibaEveryDayHelloEntity.java
│ │ │ ├── QingyunkeRobot/
│ │ │ │ ├── QingyunkeRobot.java
│ │ │ │ ├── QingyunkeWeather/
│ │ │ │ │ ├── QingWeather.java
│ │ │ │ │ ├── QingWeatherCityId.java
│ │ │ │ │ └── entity/
│ │ │ │ │ ├── QingWeatherCityEntity.java
│ │ │ │ │ └── QingWeatherEntity.java
│ │ │ │ └── entity/
│ │ │ │ └── QingyunkeResponseEntity.java
│ │ │ ├── RollToolsApi/
│ │ │ │ ├── RollNews.java
│ │ │ │ ├── RollWeather.java
│ │ │ │ └── entity/
│ │ │ │ ├── RollNewsContentEntity.java
│ │ │ │ ├── RollNewsDetailsEntity.java
│ │ │ │ ├── RollNewsEntity.java
│ │ │ │ └── RollWeatherEntity.java
│ │ │ ├── RubbishClassificationApp/
│ │ │ │ └── RubbishApp.java
│ │ │ └── Zhihu/
│ │ │ ├── ZhihuHot.java
│ │ │ └── entity/
│ │ │ ├── ZhihuHotContentEntity.java
│ │ │ ├── ZhihuHotDetailEntity.java
│ │ │ └── ZhihuHotEntity.java
│ │ ├── schedule/
│ │ │ ├── EverydayHelloSchedule.java
│ │ │ ├── base/
│ │ │ │ └── BaseScheduleTask.java
│ │ │ └── task/
│ │ │ ├── FriendEverydayTask.java
│ │ │ └── GroupEverydayTask.java
│ │ └── utils/
│ │ ├── AtMeMsg.java
│ │ ├── DateUtil.java
│ │ ├── GroupMsgUtil.java
│ │ ├── HttpRequestUtil.java
│ │ ├── QRCodeUtil.java
│ │ ├── ScheduleUtil.java
│ │ └── ThreadPoolUtil.java
│ └── resources/
│ ├── city.json
│ ├── config.properties
│ └── redis.properties
└── test/
└── java/
├── CacheTest.java
├── HttpTest.java
└── city.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.idea
assets
target/
# Created by .ignore support plugin (hsz.mobi)
### Java template
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
.idea/
*.iml
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
================================================
FILE: LICENSE.md
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
## 微信机器人Java版
个人微信(非公众号)微信机器人,根据指令自动回复好友消息、群聊陪聊、查天气、查垃圾分类,基于[ChatApi-WeChat](https://github.com/xuxiaoxiao-xxx/ChatApi-WeChat)构建。
<div align=center>
<img src="/doc/doc1.jpg" width = "500" height = "1500" />
</div>
### 设计理念
主要是想写一个群助手,作为在群里的工具使用。所以这个机器人响应的信息主要是以指令前缀开头的。考虑到国内手机输入法的习惯,默认指令前缀是两个问号,因为拼音9宫格的布局问号在快捷栏里,方便输入。
对于具体指令,希望汉字优先,缩写为主。
---
## 最近动态
- `fastjson`1.2.58爆出重大漏洞,升级为1.2.60
- 每日一句使用线程池调度,修复了之前使用`Timer`导致的调度稳定性差的bug
- 新增查看每日新闻命令、查看知乎热榜命令。新功能必须开启redis才能使用。
- 垃圾分类接入AToolBox接口。AToolBox的数据库更全一些,还有近似词提示,但是接口有点慢,而且必须开启Redis。如果没开启redis缓存,可以换回LAJIFENLEIAPP。
- 新增Redis缓存,可将天气查询结果、垃圾分类查询结果缓存在Redis。如果自己没有Redis,可在配置文件中关闭缓存。关闭缓存不影响现有功能,但可能后续会更新一些依赖redis实现的功能。
---
## 配置及使用
需求环境:jdk 1.8+、Maven
全局配置文件是[`resource/config.properties`](/src/main/resources/config.properties)。
缓存配置文件是[`resource/redis.properties`](/src/main/resources/redis.properties)。
程序入口:[`WechatBot.java`](/src/main/java/WechatBot.java)
启动程序后打开控制台输出的二维码链接,并使用微信扫描。
提示:任何非官方途径登陆网页微信都有可能导致封停账号登陆网页微信的权限(不影响其他端的使用)。建议使用小号。
## 激活指令
默认的指令前缀是两个问号:`??`,中英文皆可。指令前缀+具体指令组成一条完整的指令。如`北京天气`是一条天气指令,`??北京天气`是一条完整的指令,当具有天气模式权限的群里有群成员发送`??北京天气`时,此机器人会自动回复当日北京天气信息。
指令前缀可在配置文件中自定义。
### 指令举例
```
A. 获取详情
??
B. 查天气
???
??天气
??北京天气
??海淀天气
??上海天气
??深圳天气
C. 查垃圾分类
???电池
???无汞电池
???塑料袋
D. 当日新闻
??新闻
E. 知乎热榜
??知乎
??知乎 1
??知乎2
```
### 1. 查询天气
程序监听相应群聊内容,当监听到以`天气`开始的语句便查询相应城市天气并自动发送到群聊。比如:`北京天气`、`北京市天气`。只支持国内(大部分)市、区、县查询,不支持省。小部分地区由于接口数据丢失的原因不支持。
如果监听到`?`、`天气`,会按发送人微信名片上的地址发送今日天气。
```
完整指令举例:
???
??天气
??北京天气
??上海天气
??海淀天气
```
### 2. 自动回复好友
将配置文件`autoReplyFriend`设为`true`,便自动回复好友消息。不会回复黑名单中好友。
### 3. AI陪聊
此功能默认只对白名单的群或好友开放。机器人会回复任何白名单的发送者的消息。
提示:免费的机器人都是人工智障,所以此功能建议作为测试、娱乐使用。
### 4. 查询垃圾分类
当一条指令(去除前缀后)以问号`?`/`?`开头时,此指令为查询垃圾分类指令。输入具体垃圾查询垃圾分类。如`???电池`、`???无汞电池`。
```
完整指令举例:
???无汞电池
???电池
???塑料袋
???卫生纸
```
### 5. 每日一句
在配置中启用每日一句,可在指定时间向指定群发送当日天气和名言名句。当日天气使用的是`api.WeatherApi`,每日一句使用`api.EveryDayHelloApi`。
如果当日配置的时间已经过了,则会从次日开始正常执行。
向好友发送消息尚未启用。
### 6. 查看实时新闻
```
??新闻
```
### 7. 查看知乎热榜
```
??知乎
??知乎 1
??知乎 3
```
## 数据来源
### 1. 青云客
智能机器人API:https://www.sojson.com/api/semantic.html
青云客天气API:https://www.sojson.com/api/weather.html
友情提示:人工智障在线陪聊,冷场利器、分手大师。
### 2. RollToolsApi
RollToolsApi:https://github.com/MZCretin/RollToolsApi
### 3. 每日一句
金山词霸: http://open.iciba.com/dsapi/
### 4. 垃圾分类
LAJIFENLEIAPP: http://lajifenleiapp.com/
AToolBox: http://www.atoolbox.net/Tool.php?Id=804
### 5. 知乎热榜
知乎日报:https://news-at.zhihu.com/api/6/news/hot
## Acknowledgements
本项目离不开以下项目的灵感,在此对开发者表示感谢:
- [EverydayWechat](https://github.com/sfyc23/EverydayWechat)
微信助手:1.每日定时给好友发送定制消息。2.自动回复好友。 (Python)
- [xuxiaoxiao-xxx/ChatApi-WeChat](https://github.com/xuxiaoxiao-xxx/ChatApi-WeChat)
Java版本微信聊天接口,使用网页微信API,让你能够开发自己的微信聊天机器人
## License
[Apache License 2.0](https://github.com/scorego/WechatRobot/blob/master/LICENSE.md)
================================================
FILE: doc/OLD_README.md
================================================
## 微信机器人
自动回复好友消息、群聊陪聊、查询天气,基于[ChatApi-WeChat](https://github.com/xuxiaoxiao-xxx/ChatApi-WeChat)构建。
---
## TODO
- [x] @自己消息的识别
- [ ] 每日一句
- [ ] 下载二维码并打印到控制台
---
### 配置及使用
配置文件是[`resource/config.properties`](https://github.com/scorego/WechatRobot/blob/master/src/main/resources/config.properties)。
程序入口:`main/WechatBot.java`
启动程序后使用微信扫描控制台输出的二维码。
提示:任何非官方途径登陆网页微信都有可能导致封停账号登陆网页微信的权限。建议使用小号。
#### 1. 查询天气
程序监听相应群聊内容,当监听到以`天气`开始或结尾的语句便查询相应城市天气并自动发送到群聊。比如:`北京天气`、`北京市天气`、`天气北京`。只支持国内部分(大部分)市、区、县查询,不支持省。由于一些区和市同名,所以查询区天气时需要全称,如:`海淀区`。查询市及县可以不带`市`或`县`字。
如果监听到`天气`或者`天气预报`,会按发送人微信名片上的地址发送今日天气。
#### 2. 自动回复好友
将配置文件`autoReplyFriend`设为`true`,便自动回复好友消息。
#### 3. 聊天
由于免费的机器人都是人工智障,所以此功能建议作为测试、娱乐使用,也可以自己扩展接口。此功能默认只对白名单的群或好友开放。
### 数据来源
#### 1. 青云客
智能机器人API:https://www.sojson.com/api/semantic.html
青云客天气API:https://www.sojson.com/api/weather.html
友情提示:人工智障在线陪聊,冷场利器、分手大师。
#### 2. RollToolsApi
RollToolsApi:https://github.com/MZCretin/RollToolsApi
### LICENSE
[MIT](https://github.com/scorego/WechatRobot/blob/master/LICENSE.md)
================================================
FILE: pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>wang.javior</groupId>
<artifactId>wechatBot</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<encoding>UTF-8</encoding>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>me.xuxiaoxiao</groupId>
<artifactId>chatapi-wechat</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.60</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.1.0-m3</version>
</dependency>
</dependencies>
</project>
================================================
FILE: src/main/java/IdentifyCommand/CheckCommandType.java
================================================
package IdentifyCommand;
import enums.CommandType;
import org.apache.commons.lang3.StringUtils;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/20 15:38
*/
public class CheckCommandType {
private static volatile CheckCommandType Instance;
private CheckCommandType() {
}
public static CheckCommandType getInstance() {
if (Instance == null) {
synchronized (CheckCommandType.class) {
if (Instance == null) {
Instance = new CheckCommandType();
}
}
}
return Instance;
}
public CommandType checkCommandType(String content) {
if (content == null) {
return CommandType.COMMAND_NOT_EXIST;
}
if (StringUtils.isBlank(content)) {
return CommandType.COMMAND_HELP;
}
if (isRubbishCommand(content)) {
return CommandType.COMMAND_RUBBISH;
}
if (isWeatherCommand(content)) {
return CommandType.COMMAND_WEATHER;
}
if (isNewsCommand(content)) {
return CommandType.COMMAND_NEWS;
}
if (isZhihuHotCommand(content)) {
return CommandType.COMMAND_ZHIHU_HOT;
}
if (isDiDiCommand(content)) {
return CommandType.COMMAND_DIDI;
}
if (isVoteCommand(content)) {
return CommandType.COMMAND_VOTE;
}
return CommandType.COMMAND_DEFAULT;
}
private boolean isWeatherCommand(String content) {
return content.endsWith("天气");
}
private boolean isNewsCommand(String content) {
return content.startsWith("新闻");
}
private boolean isRubbishCommand(String content) {
return (content.startsWith("?") || content.startsWith("?"));
}
private boolean isZhihuHotCommand(String content) {
return (content.startsWith("知乎"));
}
private boolean isDiDiCommand(String content) {
return false;
}
private boolean isVoteCommand(String content) {
return false;
}
}
================================================
FILE: src/main/java/IdentifyCommand/PreProcessMessage.java
================================================
package IdentifyCommand;
import config.GlobalConfig;
import lombok.extern.slf4j.Slf4j;
import me.xuxiaoxiao.chatapi.wechat.entity.message.WXMessage;
import org.apache.commons.lang3.StringUtils;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/20 15:20
*/
@Slf4j
public class PreProcessMessage {
/**
* 配置文件中配置的指令前缀;为空时不生效
*/
private static final String CONFIG_COMMAND_PREFIX = GlobalConfig.getValue("commandPrefix", "");
/**
* 如果配置文件中没配置指令前缀,默认是两个问号
*/
private static final boolean IS_DEFAULT_COMMAND_PREFIX;
/**
* 指令前缀的长度
*/
private static final int COMMAND_PREFIX_LENGTH;
static {
IS_DEFAULT_COMMAND_PREFIX = StringUtils.isBlank(CONFIG_COMMAND_PREFIX);
COMMAND_PREFIX_LENGTH = IS_DEFAULT_COMMAND_PREFIX ? 2 : CONFIG_COMMAND_PREFIX.length();
}
public static boolean isCommand(WXMessage message) {
String content = message.content;
if (StringUtils.isBlank(content) || content.length() < COMMAND_PREFIX_LENGTH) {
return false;
}
return startWithCommandPrefix(content);
}
private static boolean startWithCommandPrefix(String content) {
if (IS_DEFAULT_COMMAND_PREFIX) {
char[] arr = content.toCharArray();
// 中文或者英文问号均可
return (arr[0] == '?' || arr[0] == '?') && (arr[1] == '?' || arr[1] == '?');
} else {
return CONFIG_COMMAND_PREFIX.equals(content.substring(0, 2));
}
}
public static String getCommandPrefix() {
return IS_DEFAULT_COMMAND_PREFIX ? "??" : CONFIG_COMMAND_PREFIX;
}
public static String getCommandPrefix(boolean isEnglish) {
if (isEnglish){
return IS_DEFAULT_COMMAND_PREFIX ? "??" : CONFIG_COMMAND_PREFIX;
}
return getCommandPrefix();
}
public static void removeCommandFix(WXMessage message) {
String content = message.content;
if (StringUtils.isBlank(content) || content.length() < COMMAND_PREFIX_LENGTH) {
return;
}
message.content = content.substring(COMMAND_PREFIX_LENGTH).trim();
log.info("PreProcessMessage::removeCommandFix, content:{}, newContent:{}", content, message.content);
}
}
================================================
FILE: src/main/java/WechatBot.java
================================================
import main.WechatBotClient;
/**
* @author scorego <javior@qq.com>
* @date 2019/9/20 23:30
*/
public class WechatBot {
public static void main(String[] args) {
WechatBotClient.run(args);
}
}
================================================
FILE: src/main/java/api/ChatApi.java
================================================
package api;
import config.GlobalConfig;
import lombok.extern.slf4j.Slf4j;
import me.xuxiaoxiao.chatapi.wechat.entity.message.WXMessage;
import robot.QingyunkeRobot.QingyunkeRobot;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/17 14:04
*/
@Slf4j
public class ChatApi {
private static final String CHAT_ROBOT = GlobalConfig.getValue("chatApi", "");
public static String chat(WXMessage message) {
String keyword = message.content.trim();
log.info("ChatApi::chat, keyword: {}", keyword);
switch (CHAT_ROBOT) {
case "QingyunkeRobot":
return QingyunkeRobot.getResponse(keyword);
default:
return null;
}
}
}
================================================
FILE: src/main/java/api/EveryDayHelloApi.java
================================================
package api;
import config.GlobalConfig;
import cons.WxMsg;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import robot.Ciba.CibaEveryDayHello;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/18 12:27
*/
@Slf4j
public class EveryDayHelloApi {
private static final String EVERYDAY_HELLO_API = GlobalConfig.getValue("everydayHelloApi", "");
private static final String EVERYDAY_HELLO_WEATHER_CITY = GlobalConfig.getValue("everydayHello.weather.city", "北京");
private static String DEFAULT_EVERYDAY_HELLO = GlobalConfig.getValue("everydayHello.default", "");
private static String EVERYDAY_HELLO_PREFIX = GlobalConfig.getValue("everydayHello.prefix", "");
static {
if (StringUtils.isNotBlank(DEFAULT_EVERYDAY_HELLO)) {
DEFAULT_EVERYDAY_HELLO += WxMsg.LINE;
}
if (StringUtils.isNotBlank(EVERYDAY_HELLO_PREFIX)) {
EVERYDAY_HELLO_PREFIX += WxMsg.LINE;
}
}
public static String getGroupHelloMsg() {
String msg = getMsg();
String weatherMsg = WeatherApi.getWeatherByCityName(EVERYDAY_HELLO_WEATHER_CITY);
if (StringUtils.isBlank(weatherMsg)) {
weatherMsg = WeatherApi.getWeatherByCityName("北京");
}
return EVERYDAY_HELLO_PREFIX
+ msg
+ "-------" + WxMsg.LINE
+ weatherMsg
+ "【详情】了解更多请发送??" + WxMsg.LINE;
}
public static String getFriendHelloMsg() {
// 暂未启用
return "";
}
private static String getMsg() {
String result;
switch (EVERYDAY_HELLO_API) {
case "Ciba":
result = CibaEveryDayHello.getCibaEveryday();
break;
default:
result = null;
}
if (StringUtils.isBlank(result)) {
result = DEFAULT_EVERYDAY_HELLO;
}
return result;
}
}
================================================
FILE: src/main/java/api/HelpMsg.java
================================================
package api;
import IdentifyCommand.PreProcessMessage;
import config.GlobalConfig;
import cons.WxMsg;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/20 16:10
*/
public class HelpMsg {
private static final String README_LINK = GlobalConfig.getValue("helpMsg.detail", "https://github.com/scorego/WechatRobot");
public static String getHelpMsg() {
String commandPrefix = PreProcessMessage.getCommandPrefix();
return "WeChat指令聊天机器人" + WxMsg.LINE
+ "【指令前缀】" + commandPrefix + WxMsg.LINE
+ "【天气查询】" + commandPrefix + "北京天气" + WxMsg.LINE
+ "【垃圾分类】" + commandPrefix + "?塑料袋" + WxMsg.LINE
+ "【当日新闻】" + commandPrefix + "新闻" + WxMsg.LINE
+ "【知乎热榜】" + commandPrefix + "知乎" + WxMsg.LINE
+ "【尝试一下】试着发一下\"" + PreProcessMessage.getCommandPrefix() + "?\"" + WxMsg.LINE
+ "【MORE】详情见" + README_LINK + WxMsg.LINE;
}
}
================================================
FILE: src/main/java/api/NewsApi.java
================================================
package api;
import config.RedisConfig;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import me.xuxiaoxiao.chatapi.wechat.entity.message.WXMessage;
import org.apache.commons.lang3.StringUtils;
import robot.RollToolsApi.RollNews;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/7 16:01
*/
@Slf4j
public class NewsApi {
// 510 代表科技新闻
private static final String DEFAULT_NEWS_TYPE_ID = "510";
public static String dealNewsMsg(WXMessage message) {
if (!RedisConfig.isRedisEnable()) {
return null;
}
String keyword = message.content.trim();
if (StringUtils.isBlank(keyword)) {
return null;
}
return getTodayNews(keyword);
}
public static String getTodayNews(@NonNull String keyword) {
if (!RedisConfig.isRedisEnable()) {
return null;
}
return ("新闻".equals(keyword)) ? getTodayTotalNews() : null;
}
private static String getTodayTotalNews() {
return RollNews.getTodayTotalNews(DEFAULT_NEWS_TYPE_ID, 10);
}
// private static String getToadyNewsByIndex(String newsIndex) {
// return RollNews.getToadyNewsByIndex(DEFAULT_NEWS_TYPE_ID, newsIndex);
// }
}
================================================
FILE: src/main/java/api/RubbishApi.java
================================================
package api;
import api.entity.RubbishToolBoxResponseEntity;
import cache.redis.RubbishLinkCacheFactory;
import cache.redis.RubbishTypeCacheFactory;
import cache.redis.entity.RubbishCacheEntity;
import cache.redis.entity.RubbishLinkCacheEntity;
import config.GlobalConfig;
import config.RedisConfig;
import cons.WxMsg;
import enums.RubbishType;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import me.xuxiaoxiao.chatapi.wechat.entity.message.WXMessage;
import org.apache.commons.lang3.StringUtils;
import robot.AToolBox.ToolBoxRubbish;
import robot.RubbishClassificationApp.RubbishApp;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/1 21:41
*/
@Slf4j
public class RubbishApi {
private static final boolean REDIS_ENABLE = RedisConfig.isRedisEnable();
private static final String RUBBISH_API = GlobalConfig.getValue("rubbishApi", "");
/**
* 总入口
*
* @param message
* @return
*/
public static String dealRubbishMsg(WXMessage message) {
String content = message.content.trim().substring(1).trim();
if (StringUtils.isBlank(content)) {
return null;
}
return classifyRubbish(content);
}
/**
* 根据垃圾名返回回复的消息,包括数据库无记录等情况的处理
*
* @param rubbish
* @return
*/
public static String classifyRubbish(String rubbish) {
RubbishToolBoxResponseEntity entity = new RubbishToolBoxResponseEntity(rubbish);
RubbishType rubbishType = checkRubbishType(rubbish, entity);
String rubbishTypeString = getRubbishTypeString(rubbish, rubbishType);
String tip = getRubbishTypeTip(rubbishType, entity);
return rubbishTypeString + tip;
}
/**
* 根据垃圾名查询具体垃圾分类。如果配置缓存开启,则完成缓存逻辑
*
* @param rubbish
* @return
*/
private static RubbishType checkRubbishType(String rubbish, RubbishToolBoxResponseEntity entity) {
if (!REDIS_ENABLE) {
return getRubbishTypeFromApi(rubbish, entity);
}
RubbishLinkCacheEntity rubbishLinkCacheEntity = RubbishLinkCacheFactory.getRubbishLinkCache(rubbish);
entity.setLinkRubbishString(rubbishLinkCacheEntity.get());
RubbishCacheEntity rubbishCacheEntity = RubbishTypeCacheFactory.getRubbishCacheEntity(rubbish);
RubbishType rubbishType = rubbishCacheEntity.getRubbishType();
if (rubbishType != null && rubbishType != RubbishType.NO_RESPONSE && rubbishLinkCacheEntity.get() != null) {
log.info("RubbishApi::checkRubbishType, get from cache >> rubbish: {}, result: {}", rubbish, rubbishType);
return rubbishType;
}
// 缓存无记录,查询并更新缓存
log.info("RubbishApi::checkRubbishType, cannot get from cache >> rubbish: {}", rubbish);
rubbishType = getRubbishTypeFromApi(rubbish, entity);
if (rubbishType == null) {
rubbishType = RubbishType.NO_RESPONSE;
rubbishLinkCacheEntity.setValue(ToolBoxRubbish.RUBBISH_LINK_NO_RESPONSE);
}
rubbishCacheEntity.setValue(rubbishType).save();
entity.setLinkRubbishString(rubbishLinkCacheEntity.get());
log.info("RubbishApi::checkRubbishType, update cache >> rubbish: {}, result: {}", rubbish, rubbishType);
return rubbishType;
}
/**
* 使用API查询垃圾分类,不走缓存
*
* @param rubbish
* @return
*/
private static RubbishType getRubbishTypeFromApi(String rubbish, RubbishToolBoxResponseEntity entity) {
RubbishType result;
switch (RUBBISH_API) {
case "LaJjFenLeiAPP":
result = RubbishApp.getRubbishType(rubbish);
break;
case "AToolBox":
result = ToolBoxRubbish.getRubbishType(rubbish, entity);
break;
default:
result = RubbishType.NO_RESPONSE;
}
log.info("RubbishApi::getRubbishTypeFromApi, rubbishRobot:{}, rubbish: {}, type: {}", RUBBISH_API, rubbish, result);
return result;
}
private static String getRubbishTypeString(String rubbish, @NonNull RubbishType rubbishType) {
switch (rubbishType) {
case HAZARDOUS_WASTE:
case RECYCLABLE_WASTE:
case HOUSEHOLD_FOOD_WASTE:
case RESIDUAL_WASTE:
return "【分类结果】" + rubbish + "属于" + rubbishType.getName() + "。" + WxMsg.LINE;
case NOT_EXISTS:
case NO_RESPONSE:
default:
return "【分类结果】抱歉,未找到\"" + rubbish + "\"分类信息。" + WxMsg.LINE;
}
}
private static String getRubbishTypeTip(RubbishType type, @NonNull RubbishToolBoxResponseEntity entity) {
String result;
switch (type) {
case HAZARDOUS_WASTE:
result = "【分类介绍】有害垃圾是指废电池、废灯管、废药品、废油漆及其容器等对人体健康或者自然环境造成直接或者潜在危害的生活废弃物。" + WxMsg.LINE;
// + "【投放要求】投放时请注意轻放;易破损的请连带包装或包裹后轻放;如易挥发,请密封后投放。" + WxMsg.LINE;
break;
case RECYCLABLE_WASTE:
result = "【分类介绍】可回收物是指废纸张、废塑料、废玻璃制品、废金属、废织物等适宜回收、可循环利用的生活废弃物。" + WxMsg.LINE;
// + "【投放要求】轻投轻放;清洁干燥,避免污染,费纸尽量平整;立体包装物请清空内容物,清洁后压扁投放;有尖锐边角的、应包裹后投放。" + WxMsg.LINE;
break;
case HOUSEHOLD_FOOD_WASTE:
result = "【分类介绍】湿垃圾/厨余垃圾,指日常生活垃圾产生的容易腐烂的生物质废弃物。" + WxMsg.LINE;
// + "【投放要求】纯流质的食物垃圾(如牛奶)应直接倒进下水口;"
// + "有包装物的湿垃圾应将包装物去除后分类投放;包装物请投放到对应的可回收物或干垃圾容器。" + WxMsg.LINE;
break;
case RESIDUAL_WASTE:
result = "【分类介绍】干垃圾/其他垃圾,指除可回收物、有害垃圾、湿垃圾以外的其它生活废弃物。" + WxMsg.LINE;
// + "【投放要求】" + "尽量沥干水分;" + "难以辨识类别的生活垃圾投入干垃圾容器内。" + WxMsg.LINE;
break;
case NOT_EXISTS:
case NO_RESPONSE:
default:
result = "";
}
return result + entity.getResult();
}
private static String getLinkRubbishList(String rubbish) {
if (!REDIS_ENABLE) {
return getLinkRubbishListFromApi(rubbish);
}
RubbishLinkCacheEntity rubbishLinkListCache = RubbishLinkCacheFactory.getRubbishLinkCache(rubbish);
String result;
if ((result = rubbishLinkListCache.get()) != null && !ToolBoxRubbish.RUBBISH_LINK_NO_RESPONSE.equals(result)) {
if (ToolBoxRubbish.RUBBISH_LINK_NOT_EXIST.equals(result)) {
return "";
} else {
return result;
}
}
result = ToolBoxRubbish.getLinkRubbish(rubbish);
if (StringUtils.isBlank(result)) {
result = ToolBoxRubbish.RUBBISH_LINK_NOT_EXIST;
}
rubbishLinkListCache.setValue(result).save();
return result;
}
private static String getLinkRubbishListFromApi(String rubbish) {
String linkRubbish = ToolBoxRubbish.getLinkRubbish(rubbish);
if (ToolBoxRubbish.RUBBISH_LINK_NOT_EXIST.equals(linkRubbish) || ToolBoxRubbish.RUBBISH_LINK_NO_RESPONSE.equals(linkRubbish)) {
return "";
} else {
return linkRubbish;
}
}
}
================================================
FILE: src/main/java/api/WeatherApi.java
================================================
package api;
import cache.redis.WeatherCacheFactory;
import cache.redis.entity.WeatherCacheEntity;
import config.GlobalConfig;
import config.RedisConfig;
import cons.WxMsg;
import lombok.extern.slf4j.Slf4j;
import me.xuxiaoxiao.chatapi.wechat.entity.message.WXMessage;
import org.apache.commons.lang3.StringUtils;
import robot.QingyunkeRobot.QingyunkeWeather.QingWeather;
import robot.RollToolsApi.RollWeather;
/**
* 查询天气API
*/
@Slf4j
public class WeatherApi {
private static final String WEATHER_ROBOT = GlobalConfig.getValue("weatherApi", "");
private static final boolean REDIS_ENABLE = RedisConfig.isRedisEnable();
/**
* 天气缓存默认3小时。因为天气接口数据3小时更新一次
*/
private static final int WEATHER_CACHE_DURATION_SECONDS = 60 * 60 * 3;
/**
* 总入口
*
* @param message
* @return
*/
public static String dealWeatherMsg(WXMessage message) {
String keyword = message.content.trim();
if (StringUtils.isBlank(keyword)) {
return null;
}
if ("天气".equals(keyword)) {
return getFastWeatherCommand(message);
}
if (keyword.endsWith("天气")) {
return getWeatherByKeyword(keyword);
}
return null;
}
/**
* 快速查询天气,根据发消息的用户微信名片上的地址发送天气预报
*
* @param message
* @return
*/
private static String getFastWeatherCommand(WXMessage message) {
String fromUserCity = message.fromUser.city;
String response = getWeatherByCityName(fromUserCity);
return StringUtils.isNotBlank(response) ? response :
"抱歉,未获取到您所在城市。输入指定市/区/县查天气,如\"北京天气\"。" + WxMsg.LINE;
}
/**
* 根据关键字查询天气接口
*
* @param keyword 关键字指以“天气”开头的词,举例:北京天气
* @return 查询到天气返回天气;未查询到返回抱歉语句。
*/
public static String getWeatherByKeyword(String keyword) {
if (StringUtils.isBlank(WEATHER_ROBOT)) {
return null;
}
String cityName = keyword.substring(0, keyword.length() - 2).trim();
String response = getWeatherByCityName(cityName);
if (StringUtils.isBlank(response)) {
response = "抱歉,未查询到\"" + keyword + "\"。" + "只支持查询国内(部分)市/区/县天气。" + WxMsg.LINE;
}
log.info("WeatherApi::getWeatherByKeyword, keyword:{}, cityName:{},response:{}", keyword, cityName, response);
return response;
}
/**
* 根据城市名查询今日天气。未查询到返回null
*
* @param cityName
* @return
*/
public static String getWeatherByCityName(String cityName) {
if (!REDIS_ENABLE) {
return getWeatherFromApi(cityName);
}
WeatherCacheEntity weatherCacheEntity = WeatherCacheFactory.getWeatherCacheEntity(cityName);
String result = weatherCacheEntity.get();
if (result != null) {
log.info("WeatherApi::getWeatherByCityName, get from cache >> cityName: {}, result: {}", cityName, result);
return result;
}
// 缓存无数据
log.info("WeatherApi::getWeatherByCityName, cannot get from cache >> cityName: {}", cityName);
result = getWeatherFromApi(cityName);
if (weatherCacheEntity.setValue(result).save()) {
log.info("WeatherApi::getWeatherByCityName, update cache >> cityName: {}, result: {}", cityName, result);
}
return result;
}
private static String getWeatherFromApi(String cityName) {
String result;
switch (WEATHER_ROBOT) {
case "QingyunkeRobot":
result = QingWeather.getWeatherByCityName(cityName);
break;
case "RollToolsApi":
result = RollWeather.getWeatherByCityName(cityName);
break;
default:
result = null;
}
log.info("WeatherApi:getWeatherFromApi, WEATHER_ROBOT:{}, cityName:{}, result: {}", WEATHER_ROBOT, cityName, result);
return result;
}
}
================================================
FILE: src/main/java/api/ZhihuHotApi.java
================================================
package api;
import config.RedisConfig;
import me.xuxiaoxiao.chatapi.wechat.entity.message.WXMessage;
import robot.Zhihu.ZhihuHot;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/7 18:57
*/
public class ZhihuHotApi {
public static String dealZhihuHotMsg(WXMessage message) {
if (RedisConfig.isRedisNotEnable()) {
return null;
}
String keyword = message.content.trim();
if ("知乎".equals(keyword)) {
return ZhihuHot.getZhihuHot();
}
int index = 0;
try {
index = Integer.valueOf(keyword.substring(2).trim());
} catch (NumberFormatException e) {
return "输入序列号错误。";
}
return ZhihuHot.getSingleZhihuHot(index - 1);
}
}
================================================
FILE: src/main/java/api/entity/RubbishToolBoxResponseEntity.java
================================================
package api.entity;
import cons.WxMsg;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import robot.AToolBox.ToolBoxRubbish;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/5 16:00
*/
@Data
public class RubbishToolBoxResponseEntity {
private String rubbish;
private String response;
private String linkRubbishString;
public RubbishToolBoxResponseEntity(String rubbish) {
this.rubbish = rubbish;
}
public String getResult() {
if (StringUtils.isBlank(linkRubbishString) || linkRubbishString.equals(ToolBoxRubbish.RUBBISH_LINK_NOT_EXIST)) {
return "";
}
if (linkRubbishString.equals(ToolBoxRubbish.RUBBISH_LINK_NO_RESPONSE)) {
return "";
}
return "【相关词条】" + linkRubbishString.trim() + WxMsg.LINE;
}
}
================================================
FILE: src/main/java/cache/redis/NewsCacheFactory.java
================================================
package cache.redis;
import cache.redis.entity.NewsCacheEntity;
import cache.redis.entity.WeatherCacheEntity;
import utils.DateUtil;
import java.util.Date;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/7 16:21
*/
public class NewsCacheFactory {
/**
* 新闻缓存默认1小时。
*/
private static final int NEWS_CACHE_DURATION_SECONDS = 60 * 60;
/**
* 单条新闻缓存时间为24小时
*/
private static final int SINGLE_NEWS_CACHE_DURATION_SECONDS = 60 * 60 * 24;
public static NewsCacheEntity getNewsCacheEntity(String typeId, String date, int limit) {
WeatherCacheEntity.KeyBuilder keyBuilder = new NewsCacheEntity.KeyBuilder("news")
.addParam("typeId", typeId)
.addParam("limit", limit)
.addParam("date", date);
return new NewsCacheEntity(keyBuilder, NEWS_CACHE_DURATION_SECONDS);
}
public static NewsCacheEntity getNewsCacheEntity(String typeId, int limit) {
String today = DateUtil.getCacheFormatDate(new Date());
WeatherCacheEntity.KeyBuilder keyBuilder = new NewsCacheEntity.KeyBuilder("news")
.addParam("typeId", typeId)
.addParam("limit", limit)
.addParam("date", today);
return new NewsCacheEntity(keyBuilder, NEWS_CACHE_DURATION_SECONDS);
}
public static NewsCacheEntity getSingleNewsCacheEntity(String newsId) {
String today = DateUtil.getCacheFormatDate(new Date());
WeatherCacheEntity.KeyBuilder keyBuilder = new NewsCacheEntity.KeyBuilder("news")
.addParam("newsId", newsId);
return new NewsCacheEntity(keyBuilder, SINGLE_NEWS_CACHE_DURATION_SECONDS);
}
}
================================================
FILE: src/main/java/cache/redis/RubbishLinkCacheFactory.java
================================================
package cache.redis;
import cache.redis.entity.RubbishLinkCacheEntity;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/5 13:39
*/
public class RubbishLinkCacheFactory {
private static final int RUBBISH_LINK_CACHE_DURATION_SECONDS = 0;
public static RubbishLinkCacheEntity getRubbishLinkCache(String rubbish) {
RubbishLinkCacheEntity.KeyBuilder KeyBuilder = new RubbishLinkCacheEntity.KeyBuilder("rubbishLink").addParam("item", rubbish);
return new RubbishLinkCacheEntity(KeyBuilder, RUBBISH_LINK_CACHE_DURATION_SECONDS);
}
}
================================================
FILE: src/main/java/cache/redis/RubbishTypeCacheFactory.java
================================================
package cache.redis;
import cache.redis.entity.RubbishCacheEntity;
import lombok.NonNull;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/4 16:04
*/
public class RubbishTypeCacheFactory {
/**
* 缓存key过期时间。<= 0为不过期
*/
private static final int RUBBISH_CACHE_DURATION_SECONDS = 0;
public static RubbishCacheEntity getRubbishCacheEntity(@NonNull String rubbish) {
RubbishCacheEntity.KeyBuilder KeyBuilder = new RubbishCacheEntity.KeyBuilder("rubbishType").addParam("item", rubbish);
return new RubbishCacheEntity(KeyBuilder, RUBBISH_CACHE_DURATION_SECONDS);
}
}
================================================
FILE: src/main/java/cache/redis/WeatherCacheFactory.java
================================================
package cache.redis;
import cache.redis.entity.WeatherCacheEntity;
import utils.DateUtil;
import java.util.Date;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/4 16:29
*/
public class WeatherCacheFactory {
/**
* 天气缓存默认3小时。因为天气接口数据3小时更新一次
*/
private static final int WEATHER_CACHE_DURATION_SECONDS = 60 * 60 * 3;
public static WeatherCacheEntity getWeatherCacheEntity(String cityName, String date) {
WeatherCacheEntity.KeyBuilder keyBuilder = new WeatherCacheEntity.KeyBuilder("weather")
.addParam("city", cityName)
.addParam("date", date);
return new WeatherCacheEntity(keyBuilder, WEATHER_CACHE_DURATION_SECONDS);
}
public static WeatherCacheEntity getWeatherCacheEntity(String cityName) {
String today = DateUtil.getCacheFormatDate(new Date());
WeatherCacheEntity.KeyBuilder keyBuilder = new WeatherCacheEntity.KeyBuilder("weather")
.addParam("city", cityName)
.addParam("date", today);
return new WeatherCacheEntity(keyBuilder, WEATHER_CACHE_DURATION_SECONDS);
}
}
================================================
FILE: src/main/java/cache/redis/ZhihuHotCacheFactory.java
================================================
package cache.redis;
import cache.redis.entity.WeatherCacheEntity;
import cache.redis.entity.ZhihuHotCacheEntity;
import utils.DateUtil;
import java.util.Date;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/7 16:21
*/
public class ZhihuHotCacheFactory {
/**
* 新闻缓存默认1小时。
*/
private static final int ZHI_HU_HOT_CACHE_DURATION_SECONDS = 60 * 60;
// private static final int ZHI_HU_HOT_CACHE_DURATION_SECONDS = 60;
/**
* 单条新闻缓存时间为30天
*/
private static final int SINGLE_ZHI_HU_HOT_CACHE_DURATION_SECONDS = 60 * 60 * 24 * 30;
public static ZhihuHotCacheEntity getZhihuHotCacheEntity(String date, int limit) {
WeatherCacheEntity.KeyBuilder keyBuilder = new ZhihuHotCacheEntity.KeyBuilder("zhihu")
.addParam("limit", limit)
.addParam("date", date);
return new ZhihuHotCacheEntity(keyBuilder, ZHI_HU_HOT_CACHE_DURATION_SECONDS);
}
public static ZhihuHotCacheEntity getZhihuHotCacheEntity(int limit) {
String today = DateUtil.getCacheFormatDate(new Date());
WeatherCacheEntity.KeyBuilder keyBuilder = new ZhihuHotCacheEntity.KeyBuilder("zhihu")
.addParam("limit", limit)
.addParam("date", today);
return new ZhihuHotCacheEntity(keyBuilder, ZHI_HU_HOT_CACHE_DURATION_SECONDS);
}
public static ZhihuHotCacheEntity getSingleZhihuHotCacheEntity(long newsId) {
String today = DateUtil.getCacheFormatDate(new Date());
WeatherCacheEntity.KeyBuilder keyBuilder = new ZhihuHotCacheEntity.KeyBuilder("zhihu")
.addParam("newsId", newsId);
return new ZhihuHotCacheEntity(keyBuilder, SINGLE_ZHI_HU_HOT_CACHE_DURATION_SECONDS);
}
}
================================================
FILE: src/main/java/cache/redis/entity/NewsCacheEntity.java
================================================
package cache.redis.entity;
import cache.redis.provider.RCacheEntity;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/7 16:20
*/
public class NewsCacheEntity extends RCacheEntity {
public NewsCacheEntity(KeyBuilder keyBuilder) {
super(keyBuilder);
}
public NewsCacheEntity(KeyBuilder keyBuilder, int expireSeconds) {
super(keyBuilder, expireSeconds);
}
}
================================================
FILE: src/main/java/cache/redis/entity/RubbishCacheEntity.java
================================================
package cache.redis.entity;
import cache.redis.provider.RCacheEntity;
import enums.RubbishType;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/4 16:07
*/
public class RubbishCacheEntity extends RCacheEntity {
public RubbishCacheEntity(KeyBuilder keyBuilder) {
super(keyBuilder);
}
public RubbishCacheEntity(KeyBuilder keyBuilder, int expireSeconds) {
super(keyBuilder, expireSeconds);
}
public RubbishType getRubbishType() {
String stringType = get();
if (stringType == null) {
return null;
}
return RubbishType.findByValue(Integer.valueOf(stringType));
}
public RubbishCacheEntity setValue(RubbishType rubbishType) {
this.setValue(String.valueOf(rubbishType.getValue()));
return this;
}
}
================================================
FILE: src/main/java/cache/redis/entity/RubbishLinkCacheEntity.java
================================================
package cache.redis.entity;
import cache.redis.provider.RCacheEntity;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/5 13:38
*/
public class RubbishLinkCacheEntity extends RCacheEntity {
public RubbishLinkCacheEntity(KeyBuilder keyBuilder) {
super(keyBuilder);
}
public RubbishLinkCacheEntity(KeyBuilder keyBuilder, int expireSeconds) {
super(keyBuilder, expireSeconds);
}
}
================================================
FILE: src/main/java/cache/redis/entity/WeatherCacheEntity.java
================================================
package cache.redis.entity;
import cache.redis.provider.RCacheEntity;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/4 16:33
*/
public class WeatherCacheEntity extends RCacheEntity {
public WeatherCacheEntity(KeyBuilder keyBuilder) {
super(keyBuilder);
}
public WeatherCacheEntity(KeyBuilder keyBuilder, int expireSeconds) {
super(keyBuilder, expireSeconds);
}
}
================================================
FILE: src/main/java/cache/redis/entity/ZhihuHotCacheEntity.java
================================================
package cache.redis.entity;
import cache.redis.provider.RCacheEntity;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/7 19:06
*/
public class ZhihuHotCacheEntity extends RCacheEntity {
public ZhihuHotCacheEntity(KeyBuilder keyBuilder) {
super(keyBuilder);
}
public ZhihuHotCacheEntity(KeyBuilder keyBuilder, int expireSeconds) {
super(keyBuilder, expireSeconds);
}
}
================================================
FILE: src/main/java/cache/redis/provider/BaseRedisCache.java
================================================
package cache.redis.provider;
import redis.clients.jedis.Jedis;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/2 20:30
*/
public class BaseRedisCache {
private static volatile BaseRedisCache INSTANCE;
public static BaseRedisCache getInstance() {
if (INSTANCE == null) {
synchronized (BaseRedisCache.class) {
if (INSTANCE == null) {
INSTANCE = new BaseRedisCache();
}
}
}
return INSTANCE;
}
private BaseRedisCache() {
}
private final static String REDIS_OK = "OK";
public boolean setex(String key, String value, int seconds) {
Jedis jedis = JedisPoolUtil.getJedis();
String result = jedis.setex(key, seconds, value);
jedis.close();
return REDIS_OK.equals(result);
}
public boolean set(String key, String value) {
Jedis jedis = JedisPoolUtil.getJedis();
String result = jedis.set(key, value);
jedis.close();
return REDIS_OK.equals(result);
}
public String get(String key) {
Jedis jedis = JedisPoolUtil.getJedis();
String result = jedis.get(key);
jedis.close();
return result;
}
public boolean del(String key) {
Jedis jedis = JedisPoolUtil.getJedis();
Long result = jedis.del(key);
jedis.close();
return result != null && result > 0;
}
}
================================================
FILE: src/main/java/cache/redis/provider/JedisPoolUtil.java
================================================
package cache.redis.provider;
import config.RedisConfig;
import org.apache.commons.lang3.StringUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/2 21:36
*/
public class JedisPoolUtil {
private final static String HOST = RedisConfig.getValue("redis.host", "");
private final static int PORT = Integer.valueOf(RedisConfig.getValue("redis.port", "6379"));
private final static String PASSWORD = RedisConfig.getValue("redis.password", "");
private static JedisPool pool;
/**
* 获取一个Jedis 对象
*
* @return
*/
public static Jedis getJedis() {
if (pool == null)
poolInit();
Jedis resource = pool.getResource();
if (StringUtils.isNotBlank(PASSWORD)){
resource.auth(PASSWORD);
}
return resource;
}
private static void createJedisPool() {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(10);
config.setMaxIdle(10);
config.setMaxWaitMillis(1000 * 10);
// 创建连接池
pool = new JedisPool(config, HOST, PORT);
}
private static synchronized void poolInit() {
if (pool == null)
createJedisPool();
}
}
================================================
FILE: src/main/java/cache/redis/provider/RCacheEntity.java
================================================
package cache.redis.provider;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import java.util.Map;
import java.util.TreeMap;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/2 20:20
*/
public class RCacheEntity {
private String value;
@Setter
@Getter
private KeyBuilder keyBuilder;
/**
* 默认缓存时间是24小时
*/
@Getter
@Setter
private int expireSeconds = 60 * 60 * 24;
private BaseRedisCache baseRedisCache = BaseRedisCache.getInstance();
public boolean save() {
if (StringUtils.isEmpty(value)) {
return false;
}
if (expireSeconds > 0) {
return baseRedisCache.setex(getKey(), value, expireSeconds);
} else {
return baseRedisCache.set(getKey(), value);
}
}
public String get() {
return baseRedisCache.get(getKey());
}
public boolean del() {
return baseRedisCache.del(getKey());
}
public RCacheEntity(KeyBuilder keyBuilder) {
this.keyBuilder = keyBuilder;
}
public RCacheEntity(KeyBuilder keyBuilder, int expireSeconds) {
this.keyBuilder = keyBuilder;
this.expireSeconds = expireSeconds;
}
public RCacheEntity setValue(String value) {
this.value = value;
return this;
}
private String getKey() {
return keyBuilder.build();
}
public static class KeyBuilder {
Map<String, Object> keyMap = new TreeMap<>();
@Setter
String name;
@Setter
String key;
public KeyBuilder(String name) {
this.name = (name == null) ? "" : name;
}
public KeyBuilder addParam(String name, Object object) {
keyMap.put(name, object);
return this;
}
private String build() {
StringBuilder result = new StringBuilder(name);
if (StringUtils.isEmpty(key)) {
for (Map.Entry<String, Object> entry : keyMap.entrySet()) {
result.append(":").append(entry.getKey()).append(":").append(entry.getValue());
}
} else {
result = new StringBuilder(key);
}
return result.toString();
}
}
}
================================================
FILE: src/main/java/config/GlobalConfig.java
================================================
package config;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
@Slf4j
public class GlobalConfig {
private static Properties pp;
static {
pp = new Properties();
try {
pp.load(new InputStreamReader(GlobalConfig.class.getResourceAsStream("/config.properties"), StandardCharsets.UTF_8));
} catch (Exception e) {
log.error("读取config.properties文件异常!", e);
}
}
public static String getValue(String key, String defaultValue) {
if (StringUtils.isBlank(key)) {
return defaultValue;
}
String value = pp.getProperty(key);
return StringUtils.isBlank(value) ? defaultValue : value;
}
}
================================================
FILE: src/main/java/config/QingWeatherCityConfig.java
================================================
package config;
import com.alibaba.fastjson.JSON;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import robot.QingyunkeRobot.QingyunkeWeather.entity.QingWeatherCityEntity;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class QingWeatherCityConfig {
private static final String CITY_JSON_FILE = GlobalConfig.getValue("cityJsonFile", "");
@Getter
private List<QingWeatherCityEntity> cityList;
private static volatile QingWeatherCityConfig INSTANCE;
private QingWeatherCityConfig() {
String filePath = QingWeatherCityConfig.class.getClassLoader().getResource("").getPath() + CITY_JSON_FILE;
StringBuilder sb = new StringBuilder();
try (InputStream is = new FileInputStream(filePath)) {
String line;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}
}
cityList = JSON.parseArray(sb.toString(), QingWeatherCityEntity.class);
} catch (IOException e) {
log.error("QingWeather::读取city数据出错!", e);
} finally {
if (cityList == null) {
cityList = new ArrayList<>(0);
}
}
}
public static QingWeatherCityConfig getInstance() {
if (INSTANCE == null) {
synchronized (QingWeatherCityConfig.class) {
if (INSTANCE == null) {
INSTANCE = new QingWeatherCityConfig();
}
}
}
return INSTANCE;
}
}
================================================
FILE: src/main/java/config/RedisConfig.java
================================================
package config;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
@Slf4j
public class RedisConfig {
private static Properties pp;
static {
pp = new Properties();
try {
pp.load(new InputStreamReader(RedisConfig.class.getResourceAsStream("/redis.properties"), StandardCharsets.UTF_8));
} catch (Exception e) {
log.error("读取redis.properties文件异常!", e);
}
}
public static String getValue(String key, String defaultValue) {
if (StringUtils.isBlank(key)) {
return defaultValue;
}
String value = pp.getProperty(key);
return StringUtils.isBlank(value) ? defaultValue : value;
}
public static boolean isRedisEnable() {
return "true".equalsIgnoreCase(getValue("redis.enable", "false"));
}
public static boolean isRedisNotEnable() {
return !isRedisEnable();
}
}
================================================
FILE: src/main/java/cons/WxMsg.java
================================================
package cons;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/19 18:39
*/
public class WxMsg {
/**
* 微信消息换行符
*/
public static final String LINE = "\n";
/**
* 微信群里@人后面的类似空格的字符。不是空格。如“@nickname ” \u2005 ??
*/
public static final String AT_ME_SPACE = " ";
/**
* 接收的消息内容的换行。
*/
public static final String RECEIVE_MSG_LINE = "<br/>";
}
================================================
FILE: src/main/java/enums/CommandType.java
================================================
package enums;
import lombok.Getter;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/20 15:38
*/
@Getter
public enum CommandType {
/**
* 获取详情
*/
COMMAND_HELP,
/**
* 当日新闻
*/
COMMAND_NEWS,
/**
* 知乎热榜
*/
COMMAND_ZHIHU_HOT,
/**
* 查天气
*/
COMMAND_WEATHER,
/**
* 查垃圾分类
*/
COMMAND_RUBBISH,
/**
* 拼车模式
*/
COMMAND_DIDI,
/**
* 投票模式
*/
COMMAND_VOTE,
/**
* 聊天
*/
COMMAND_CHAT,
/**
* 默认级别
*/
COMMAND_DEFAULT,
COMMAND_NOT_EXIST;
private int value;
}
================================================
FILE: src/main/java/enums/FriendType.java
================================================
package enums;
import lombok.Getter;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/17 16:49
*/
@Getter
public enum FriendType {
FRIEND_BLACK,
FRIEND_WHITE,
FRIEND_NOT_EXISTS,
FRIEND_DEFAULT;
private int value;
}
================================================
FILE: src/main/java/enums/GroupType.java
================================================
package enums;
import lombok.Getter;
@Getter
public enum GroupType {
/**
* 默认级别
*/
GROUP_DEFAULT,
/**
* 白名单,回复一切信息
*/
GROUP_WHITELIST,
/**
* 只回复启用的模式
*/
GROUP_MODE_ONLY,
/**
* 只回复@我的信息
*/
GROUP_AT_ME_ONLY,
/**
* 黑名单,不回复任何信息
*/
GROUP_BLACKLIST,
/**
* 群不存在
*/
GROUP_NOT_EXISTS;
private int status;
}
================================================
FILE: src/main/java/enums/RubbishType.java
================================================
package enums;
import lombok.Getter;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/1 21:42
*/
public enum RubbishType {
HAZARDOUS_WASTE(1, "有害垃圾"),
RECYCLABLE_WASTE(2, "可回收物"),
HOUSEHOLD_FOOD_WASTE(3, "湿垃圾/厨余垃圾"),
RESIDUAL_WASTE(4, "干垃圾/其它垃圾"),
NOT_EXISTS(5, "数据库未查到"),
NO_RESPONSE(6, "API无响应");
@Getter
private int value;
@Getter
private String name;
public static RubbishType findByValue(int value) {
switch (value) {
case 1:
return HAZARDOUS_WASTE;
case 2:
return RECYCLABLE_WASTE;
case 3:
return HOUSEHOLD_FOOD_WASTE;
case 4:
return RESIDUAL_WASTE;
case 5:
return NOT_EXISTS;
case 6:
return NO_RESPONSE;
default:
return null;
}
}
RubbishType(int value, String name) {
this.value = value;
this.name = name;
}
}
================================================
FILE: src/main/java/main/WechatBotClient.java
================================================
package main;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import config.GlobalConfig;
import cons.WxMsg;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import main.facade.DealMessage;
import me.xuxiaoxiao.chatapi.wechat.WeChatClient;
import me.xuxiaoxiao.chatapi.wechat.entity.contact.WXContact;
import me.xuxiaoxiao.chatapi.wechat.entity.message.*;
import org.apache.commons.lang3.StringUtils;
import schedule.EverydayHelloSchedule;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/18 20:06
*/
@Slf4j
public class WechatBotClient {
private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create();
private static String REPLY_PREFIX = GlobalConfig.getValue("replyPrefix", "");
static {
if (StringUtils.isNotBlank(REPLY_PREFIX)) {
REPLY_PREFIX += WxMsg.LINE;
}
}
@Getter
private static WeChatClient weChatClient;
/**
* 新建一个微信监听器
*/
private static final WeChatClient.WeChatListener LISTENER = new WeChatClient.WeChatListener() {
@Override
public void onQRCode(@Nonnull WeChatClient client, @Nonnull String qrCode) {
log.info("onQRCode:{}", qrCode);
// log.info(QRCodeUtil.printQRCode(qrCode));
}
@Override
public void onLogin(@Nonnull WeChatClient client) {
log.info("onLogin:您有{}名好友,活跃微信群{}个", client.userFriends().size(), client.userGroups().size());
}
@Override
public void onMessage(@Nonnull WeChatClient client, @Nonnull WXMessage message) {
log.info("获取到消息:{}", GSON.toJson(message));
if (message instanceof WXVerify) {
log.info("收到好友请求消息。来自:{}", message.fromUser.name);
// client.passVerify((WXVerify) message);
} else if (message instanceof WXLocation && message.fromUser != null && !message.fromUser.id
.equals(client.userMe().id)) {
if (message.fromGroup != null) {
log.info("收到位置消息。来自群: {},用户: {}", message.fromGroup.name, message.fromUser.name);
// // client.sendLocation(message.fromGroup, "120.14556", "30.23856", "我在这里",
// "西湖");
} else {
log.info("收到位置消息。来自好友: {}", message.fromUser.name);
// client.sendLocation(message.fromUser, "120.14556", "30.23856", "我在这里", "西湖");
}
} else if (message instanceof WXSystem) {
log.info("收到系统消息。msg {}", message.content);
} else if (message instanceof WXText && message.fromUser != null && !message.fromUser.id
.equals(client.userMe().id)) {
if (message.fromGroup != null) {
log.info("收到文字消息。来自群: {},用户: {},内容: {}", message.fromGroup.name, message.fromUser.name,
message.content);
String response = DealMessage.dealGroupTextMsg(message);
if (StringUtils.isNotBlank(response)) {
response = REPLY_PREFIX + response;
log.info("回复消息,to:{}, content: {}", message.fromGroup.name, response);
client.sendText(message.fromGroup, response);
}
} else {
log.info("收到文字消息。来自好友: {}", message.fromUser.name);
String response = DealMessage.dealFriendTextMsg(message);
if (StringUtils.isNotBlank(response)) {
response = REPLY_PREFIX + response;
log.info("回复消息,to:{}, content: {}", message.fromUser.name, response);
client.sendText(message.fromUser, response);
}
}
}
}
@Override
public void onContact(@Nonnull WeChatClient client, @Nullable WXContact oldContact,
@Nullable WXContact newContact) {
if (oldContact != null && newContact != null && !oldContact.name.equals(newContact.name)) {
log.info("检测到联系人变更: 旧联系人名称:{}, 新联系人名称:{}", oldContact.name, newContact.name);
}
}
};
public static void run(String[] args) {
weChatClient = new WeChatClient();
weChatClient.setListener(LISTENER);
weChatClient.startup();
// 群每日一句定时任务
EverydayHelloSchedule.startGroupEverydaySchedule();
}
}
================================================
FILE: src/main/java/main/facade/DealMessage.java
================================================
package main.facade;
import IdentifyCommand.PreProcessMessage;
import cons.WxMsg;
import lombok.extern.slf4j.Slf4j;
import main.service.friendMsg.FriendChat;
import main.service.groupMsg.GroupChat;
import me.xuxiaoxiao.chatapi.wechat.entity.message.WXMessage;
import org.apache.commons.lang3.StringUtils;
import utils.GroupMsgUtil;
@Slf4j
public class DealMessage {
public static String dealGroupTextMsg(WXMessage message) {
boolean isCommand = PreProcessMessage.isCommand(message);
String display = GroupMsgUtil.getUserDisplayOrName(message);
log.info("群:{}, 用户: {}, 群名片: {}, isCommand: {}, 内容: {}", message.fromGroup.name, message.fromUser.name, display, isCommand, message.content);
String response;
if (isCommand) {
// 是指令的话执行指令
response = DoCommand.doGroupTextCommand(message);
} else {
// 否则白名单的群陪聊
response = GroupChat.getInstance().dealGroupChatMsg(message);
}
if (StringUtils.isNotBlank(response)) {
String atMePrefix = "@" + display + WxMsg.AT_ME_SPACE + WxMsg.LINE;
return atMePrefix + response;
}
return null;
}
public static String dealFriendTextMsg(WXMessage message) {
log.info("好友:{}, 好友备注: {},内容: {}", message.fromUser.name, message.fromUser.remark, message.content);
return FriendChat.dealFriendMsg(message);
}
}
================================================
FILE: src/main/java/main/facade/DoCommand.java
================================================
package main.facade;
import IdentifyCommand.PreProcessMessage;
import lombok.extern.slf4j.Slf4j;
import main.service.groupMsg.GroupTextCommand;
import me.xuxiaoxiao.chatapi.wechat.entity.message.WXMessage;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/20 15:43
*/
@Slf4j
public class DoCommand {
public static String doGroupTextCommand(WXMessage message) {
PreProcessMessage.removeCommandFix(message);
log.info("DoCommand::doGroupTextCommand, command: {}", message.content);
return GroupTextCommand.getInstance().doGroupCommand(message);
}
}
================================================
FILE: src/main/java/main/service/everydayHelloMsg/EveryDayHelloWhiteList.java
================================================
package main.service.everydayHelloMsg;
import config.GlobalConfig;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import main.WechatBotClient;
import me.xuxiaoxiao.chatapi.wechat.entity.contact.WXGroup;
import me.xuxiaoxiao.chatapi.wechat.entity.contact.WXUser;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
import java.util.stream.Collectors;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/18 12:42
*/
@Slf4j
public class EveryDayHelloWhiteList {
private static volatile EveryDayHelloWhiteList INSTANCE;
private static final String EVERYDAY_HELLO_GROUP_WHITE_LIST = GlobalConfig.getValue("everydayHello.group.whitelist", "");
private static final String EVERYDAY_HELLO_FRIEND_WHITE_LIST = GlobalConfig.getValue("everydayHello.friend.whitelist", "");
private EveryDayHelloWhiteList() {
group = new LinkedList<>();
group.addAll(Arrays.stream(EVERYDAY_HELLO_GROUP_WHITE_LIST.split("#")).filter(StringUtils::isNotBlank).collect(Collectors.toList()));
friend = new LinkedList<>();
friend.addAll(Arrays.stream(EVERYDAY_HELLO_FRIEND_WHITE_LIST.split("#")).filter(StringUtils::isNotBlank).collect(Collectors.toList()));
groupSet = new HashSet<>(group.size());
HashMap<String, WXGroup> groupMap = WechatBotClient.getWeChatClient().userGroups();
group.forEach(g ->
groupMap.forEach((key, value) -> {
if (value.name.equals(g)) {
groupSet.add(value);
}
})
);
StringBuilder groupSetList = new StringBuilder();
for (WXGroup wxGroup : groupSet) {
groupSetList.append(wxGroup.name).append(" \t");
}
log.info("每日一句群列表:{}", groupSetList.toString());
friendSet = new HashSet<>(friend.size());
HashMap<String, WXUser> friendMap = WechatBotClient.getWeChatClient().userFriends();
friend.forEach(f ->
friendMap.forEach((key, value) -> {
if (value.name.equals(f)) {
friendSet.add(value);
}
})
);
StringBuilder friendSetList = new StringBuilder();
for (WXUser wxUser : friendSet) {
friendSetList.append(wxUser.name).append(" \t");
}
log.info("每日一句好友列表:{}", friendSetList.toString());
}
public static EveryDayHelloWhiteList getInstance() {
if (INSTANCE == null) {
synchronized (EveryDayHelloWhiteList.class) {
if (INSTANCE == null) {
INSTANCE = new EveryDayHelloWhiteList();
}
}
}
return INSTANCE;
}
@Getter
private List<String> group;
@Getter
private List<String> friend;
/**
* 要发送每日一句的群名单
*/
@Getter
private Set<WXGroup> groupSet;
/**
* 要发送每日一句的好友名单
*/
@Getter
private Set<WXUser> friendSet;
}
================================================
FILE: src/main/java/main/service/friendMsg/CheckFriendType.java
================================================
package main.service.friendMsg;
import config.GlobalConfig;
import enums.FriendType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/17 16:52
*/
@Slf4j
public class CheckFriendType {
private static final String FRIEND_BLACK = GlobalConfig.getValue("friend.blacklist", "");
private static final String FRIEND_WHITE = GlobalConfig.getValue("friend.whitelist", "");
private static List<String> FRIEND_BLACK_LIST = new ArrayList<>();
private static List<String> FRIEND_WHITE_LIST = new ArrayList<>();
private static Map<String, FriendType> cache = new ConcurrentHashMap<>();
static {
FRIEND_BLACK_LIST.addAll(Arrays.stream(FRIEND_BLACK.split("#")).filter(StringUtils::isNotBlank).collect(Collectors.toList()));
FRIEND_WHITE_LIST.addAll(Arrays.stream(FRIEND_WHITE.split("#")).filter(StringUtils::isNotBlank).collect(Collectors.toList()));
}
public static FriendType checkFriendType(String friendName) {
if (StringUtils.isEmpty(friendName)) {
return FriendType.FRIEND_NOT_EXISTS;
}
FriendType type = FriendType.FRIEND_DEFAULT;
if (cache.containsKey(friendName)) {
type = cache.getOrDefault(friendName, FriendType.FRIEND_NOT_EXISTS);
return type;
}
for (String s : FRIEND_BLACK_LIST) {
if (friendName.equals(s)) {
type = FriendType.FRIEND_BLACK;
}
}
for (String s : FRIEND_WHITE_LIST) {
if (friendName.equals(s)) {
type = FriendType.FRIEND_WHITE;
}
}
cache.put(friendName, type);
return type;
}
}
================================================
FILE: src/main/java/main/service/friendMsg/FriendChat.java
================================================
package main.service.friendMsg;
import api.ChatApi;
import config.GlobalConfig;
import enums.FriendType;
import lombok.extern.slf4j.Slf4j;
import me.xuxiaoxiao.chatapi.wechat.entity.message.WXMessage;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/17 14:41
*/
@Slf4j
public class FriendChat {
private static final boolean autoReplyFriend = GlobalConfig.getValue("autoReplyFriend", "false").equalsIgnoreCase("true");
private static final String autoReplyFriendMsg = GlobalConfig.getValue("autoReplyFriendMsg", "");
public static String dealFriendMsg(WXMessage message) {
FriendType friendType = CheckFriendType.checkFriendType(message.fromUser.name);
log.info("FriendChat::dealFriendMsg, friend: {}, friendType: {}", message.fromUser.name, friendType);
switch (friendType) {
case FRIEND_WHITE:
return autoReplyFriend ? autoReplyFriend(message) : ChatApi.chat(message);
case FRIEND_DEFAULT:
return autoReplyFriend ? autoReplyFriend(message) : null;
case FRIEND_BLACK:
default:
return null;
}
}
private static String autoReplyFriend(WXMessage message) {
return autoReplyFriendMsg;
}
}
================================================
FILE: src/main/java/main/service/groupMsg/CheckGroupType.java
================================================
package main.service.groupMsg;
import config.GlobalConfig;
import enums.GroupType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/17 16:07
*/
@Slf4j
public class CheckGroupType {
private static final String GROUP_WHITELIST = GlobalConfig.getValue("group.whitelist", "");
private static final String GROUP_WHITE_KEYWORD = GlobalConfig.getValue("group.whiteKeyword", "");
private static final String GROUP_BLACKLIST = GlobalConfig.getValue("group.blacklist", "");
private static final String GROUP_BLACK_KEYWORD = GlobalConfig.getValue("group.blackKeyword", "");
private static final String GROUP_MODE_ONLY = GlobalConfig.getValue("group.modeOnly", "");
private static final String GROUP_MODE_KEYWORD = GlobalConfig.getValue("group.modeOnlyKeyword", "");
private static List<String> WHITE_LIST = new ArrayList<>();
private static List<String> WHITE_KEYWORD_LIST = new ArrayList<>();
private static List<String> MODE_KEYWORD_LIST = new ArrayList<>();
private static List<String> MODE_ONLY_LIST = new ArrayList<>();
private static List<String> BLACK_KEYWORD_LIST = new ArrayList<>();
private static List<String> BLACK_LIST = new ArrayList<>();
static {
WHITE_LIST.addAll(Arrays.stream(GROUP_WHITELIST.split("#")).filter(StringUtils::isNotBlank).collect(Collectors.toList()));
WHITE_KEYWORD_LIST.addAll(Arrays.stream(GROUP_WHITE_KEYWORD.split("#")).filter(StringUtils::isNotBlank).collect(Collectors.toList()));
BLACK_KEYWORD_LIST.addAll(Arrays.stream(GROUP_BLACK_KEYWORD.split("#")).filter(StringUtils::isNotBlank).collect(Collectors.toList()));
BLACK_LIST.addAll(Arrays.stream(GROUP_BLACKLIST.split("#")).filter(StringUtils::isNotBlank).collect(Collectors.toList()));
MODE_ONLY_LIST.addAll(Arrays.stream(GROUP_MODE_ONLY.split("#")).filter(StringUtils::isNotBlank).collect(Collectors.toList()));
MODE_KEYWORD_LIST.addAll(Arrays.stream(GROUP_MODE_KEYWORD.split("#")).filter(StringUtils::isNotBlank).collect(Collectors.toList()));
}
private static Map<String, GroupType> cache = new ConcurrentHashMap<>();
public static GroupType checkGroupType(String from) {
if (StringUtils.isBlank(from)) {
return GroupType.GROUP_NOT_EXISTS;
}
GroupType type = GroupType.GROUP_DEFAULT;
if (cache.containsKey(from)) {
type = cache.getOrDefault(from, GroupType.GROUP_NOT_EXISTS);
return type;
}
for (String s : MODE_KEYWORD_LIST) {
if (from.contains(s)) {
type = GroupType.GROUP_MODE_ONLY;
}
}
for (String s : MODE_ONLY_LIST) {
if (from.equals(s))
type = GroupType.GROUP_MODE_ONLY;
}
for (String s : WHITE_KEYWORD_LIST) {
if (from.contains(s))
type = GroupType.GROUP_WHITELIST;
}
for (String s : WHITE_LIST) {
if (from.equals(s))
type = GroupType.GROUP_WHITELIST;
}
for (String s : BLACK_KEYWORD_LIST) {
if (from.contains(s))
type = GroupType.GROUP_BLACKLIST;
}
for (String s : BLACK_LIST) {
if (from.equals(s))
type = GroupType.GROUP_BLACKLIST;
}
cache.put(from, type);
return type;
}
}
================================================
FILE: src/main/java/main/service/groupMsg/GroupChat.java
================================================
package main.service.groupMsg;
import api.ChatApi;
import lombok.extern.slf4j.Slf4j;
import me.xuxiaoxiao.chatapi.wechat.entity.message.WXMessage;
import org.apache.commons.lang3.StringUtils;
@Slf4j
public class GroupChat {
private static volatile GroupChat INSTANCE;
private GroupChat() {
}
public static GroupChat getInstance() {
if (INSTANCE == null) {
synchronized (GroupChat.class) {
if (INSTANCE == null) {
INSTANCE = new GroupChat();
}
}
}
return INSTANCE;
}
public String dealGroupChatMsg(WXMessage message) {
String groupName = message.fromGroup.name;
switch (CheckGroupType.checkGroupType(groupName)) {
case GROUP_WHITELIST:
return dealChatMsg(message);
case GROUP_DEFAULT:
case GROUP_MODE_ONLY:
case GROUP_NOT_EXISTS:
case GROUP_BLACKLIST:
default:
return null;
}
}
private String dealChatMsg(WXMessage message) {
String keyword = message.content;
if (StringUtils.isBlank(keyword)) {
return null;
}
return ChatApi.chat(message);
}
}
================================================
FILE: src/main/java/main/service/groupMsg/GroupTextCommand.java
================================================
package main.service.groupMsg;
import IdentifyCommand.CheckCommandType;
import IdentifyCommand.PreProcessMessage;
import api.*;
import cons.WxMsg;
import me.xuxiaoxiao.chatapi.wechat.entity.message.WXMessage;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/20 15:47
*/
public class GroupTextCommand {
private static volatile GroupTextCommand INSTANCE;
private GroupTextCommand() {
}
public static GroupTextCommand getInstance() {
if (INSTANCE == null) {
synchronized (GroupTextCommand.class) {
if (INSTANCE == null) {
INSTANCE = new GroupTextCommand();
}
}
}
return INSTANCE;
}
public String doGroupCommand(WXMessage message) {
// 极速模式为查询天气
if (isFastCommand(message.content)) {
message.content = "天气";
return doGroupWeather(message);
}
switch (CheckCommandType.getInstance().checkCommandType(message.content)) {
case COMMAND_HELP:
return doGroupHelp(message);
case COMMAND_WEATHER:
return doGroupWeather(message);
case COMMAND_NEWS:
return doGroupNews(message);
case COMMAND_ZHIHU_HOT:
return doGroupZhihuHot(message);
case COMMAND_RUBBISH:
return doGroupRubbish(message);
case COMMAND_DIDI:
return doGroupDiDi(message);
case COMMAND_VOTE:
return doGroupVote(message);
case COMMAND_DEFAULT:
case COMMAND_NOT_EXIST:
default:
return null;
}
}
private boolean isFastCommand(String content) {
content = content.trim();
return "?".equals(content) || "?".equals(content);
}
private String doGroupHelp(WXMessage message) {
switch (CheckGroupType.checkGroupType(message.fromGroup.name)) {
case GROUP_MODE_ONLY:
case GROUP_WHITELIST:
return HelpMsg.getHelpMsg();
default:
return null;
}
}
private String doGroupWeather(WXMessage message) {
switch (CheckGroupType.checkGroupType(message.fromGroup.name)) {
case GROUP_MODE_ONLY:
case GROUP_WHITELIST:
return WeatherApi.dealWeatherMsg(message);
default:
return null;
}
}
private String doGroupNews(WXMessage message) {
switch (CheckGroupType.checkGroupType(message.fromGroup.name)) {
case GROUP_MODE_ONLY:
case GROUP_WHITELIST:
return NewsApi.dealNewsMsg(message);
default:
return null;
}
}
private String doGroupZhihuHot(WXMessage message) {
switch (CheckGroupType.checkGroupType(message.fromGroup.name)) {
case GROUP_MODE_ONLY:
case GROUP_WHITELIST:
return ZhihuHotApi.dealZhihuHotMsg(message);
default:
return null;
}
}
private String doGroupRubbish(WXMessage message) {
switch (CheckGroupType.checkGroupType(message.fromGroup.name)) {
case GROUP_MODE_ONLY:
case GROUP_WHITELIST:
return RubbishApi.dealRubbishMsg(message)
+ "【更多功能】了解更多请发送:" + PreProcessMessage.getCommandPrefix() +"" + WxMsg.LINE;
default:
return null;
}
}
private String doGroupDiDi(WXMessage message) {
switch (CheckGroupType.checkGroupType(message.fromGroup.name)) {
case GROUP_MODE_ONLY:
case GROUP_WHITELIST:
return "";
default:
return null;
}
}
private String doGroupVote(WXMessage message){
switch (CheckGroupType.checkGroupType(message.fromGroup.name)) {
case GROUP_MODE_ONLY:
case GROUP_WHITELIST:
return "";
default:
return null;
}
}
}
================================================
FILE: src/main/java/robot/AToolBox/ToolBoxRubbish.java
================================================
package robot.AToolBox;
import api.entity.RubbishToolBoxResponseEntity;
import cache.redis.RubbishLinkCacheFactory;
import cache.redis.RubbishTypeCacheFactory;
import cache.redis.entity.RubbishCacheEntity;
import cache.redis.entity.RubbishLinkCacheEntity;
import com.alibaba.fastjson.JSONObject;
import config.GlobalConfig;
import config.RedisConfig;
import cons.WxMsg;
import enums.RubbishType;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import utils.HttpRequestUtil;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/4 15:09
*/
@Slf4j
public class ToolBoxRubbish {
private static final String TOOL_BOX_RUBBISH = GlobalConfig.getValue("rubbish.aToolBox", "");
private static final boolean ENABLE_REDIS = RedisConfig.isRedisEnable();
public static final String RUBBISH_LINK_NOT_EXIST = "RUBBISH_LINK_NOT_EXIST";
public static final String RUBBISH_LINK_NO_RESPONSE = "RUBBISH_LINK_NO_RESPONSE";
private static String getRubbishResult(@NonNull String rubbish) {
String link = TOOL_BOX_RUBBISH;
try {
link += URLEncoder.encode(rubbish, StandardCharsets.UTF_8.toString());
} catch (UnsupportedEncodingException e) {
link += rubbish;
}
String response = HttpRequestUtil.doGet(link);
log.info("ToolBoxRubbish::getRubbishType, httpRequest >> rubbish: {}, response: {}", rubbish, response);
return response;
}
public static RubbishType getRubbishType(String rubbish, RubbishToolBoxResponseEntity entity) {
rubbish = rubbish.trim();
if (StringUtils.isBlank(rubbish)) {
cacheLinkRubbish(rubbish, RUBBISH_LINK_NOT_EXIST);
return RubbishType.NOT_EXISTS;
}
String rubbishResult = getRubbishResult(rubbish);
if (StringUtils.isBlank(rubbishResult)) {
// 接口无响应
cacheLinkRubbish(rubbish, RUBBISH_LINK_NO_RESPONSE);
return RubbishType.NO_RESPONSE;
} else if (!rubbishResult.startsWith("{")) {
// 接口没返回有效数据
cacheLinkRubbish(rubbish, RUBBISH_LINK_NOT_EXIST);
return RubbishType.NOT_EXISTS;
}
// 接口返回了有效数据
Map<String, Map<String, String>> result = JSONObject.parseObject(rubbishResult, Map.class);
if (result == null || result.isEmpty()) {
cacheLinkRubbish(rubbish, RUBBISH_LINK_NOT_EXIST);
return RubbishType.NOT_EXISTS;
}
String linkRubbishList = getLinkRubbishList(rubbish, result);
entity.setLinkRubbishString(linkRubbishList);
if (ENABLE_REDIS) {
cacheLinkRubbish(rubbish, linkRubbishList);
cacheAllResult(result);
}
String resultType = null;
for (Map.Entry<String, Map<String, String>> mapEntry : result.entrySet()) {
if (rubbish.equals(mapEntry.getValue().getOrDefault("name", ""))) {
resultType = mapEntry.getValue().getOrDefault("type", "");
break;
}
}
return getType(resultType);
}
private static RubbishType getType(String stringType) {
if (stringType == null) {
return RubbishType.NOT_EXISTS;
}
switch (stringType) {
case "干垃圾":
return RubbishType.RESIDUAL_WASTE;
case "可回收物":
return RubbishType.RECYCLABLE_WASTE;
case "湿垃圾":
return RubbishType.HOUSEHOLD_FOOD_WASTE;
case "有害垃圾":
return RubbishType.HAZARDOUS_WASTE;
default:
return RubbishType.NOT_EXISTS;
}
}
private static void cacheAllResult(Map<String, Map<String, String>> map) {
if (map == null || map.isEmpty()) {
return;
}
for (Map.Entry<String, Map<String, String>> mapEntry : map.entrySet()) {
RubbishCacheEntity rubbishCacheEntity = RubbishTypeCacheFactory.getRubbishCacheEntity(mapEntry.getValue().getOrDefault("name", ""));
rubbishCacheEntity.setValue(getType(mapEntry.getValue().getOrDefault("type", ""))).save();
}
}
private static void cacheLinkRubbish(String rubbish, String linkRubbishList) {
RubbishLinkCacheEntity rubbishLinkListCache = RubbishLinkCacheFactory.getRubbishLinkCache(rubbish);
rubbishLinkListCache.setValue(linkRubbishList).save();
}
public static String getLinkRubbish(String rubbish) {
rubbish = rubbish.trim();
if (StringUtils.isBlank(rubbish)) {
return RUBBISH_LINK_NOT_EXIST;
}
String rubbishResult = getRubbishResult(rubbish);
if (StringUtils.isBlank(rubbishResult)) {
// 接口无响应
return RUBBISH_LINK_NO_RESPONSE;
} else if (!rubbishResult.startsWith("{")) {
// 接口没返回有效数据
return RUBBISH_LINK_NOT_EXIST;
}
// 接口返回了有效数据
Map<String, Map<String, String>> resultMap = JSONObject.parseObject(rubbishResult, Map.class);
if (resultMap == null || resultMap.isEmpty()) {
return RUBBISH_LINK_NOT_EXIST;
}
return getLinkRubbishList(rubbish, resultMap);
}
private static String getLinkRubbishList(String rubbish, Map<String, Map<String, String>> map) {
if (map == null || map.isEmpty()) {
return "";
}
StringBuilder result = new StringBuilder(" ");
for (Map.Entry<String, Map<String, String>> mapEntry : map.entrySet()) {
if (!rubbish.equals(mapEntry.getValue().getOrDefault("name", rubbish))) {
result.append(mapEntry.getValue().getOrDefault("name", "")).append(" ");
}
}
String trim = result.toString().trim();
return StringUtils.isEmpty(trim) ? "" : trim + WxMsg.LINE;
}
}
================================================
FILE: src/main/java/robot/AToolBox/entity/ToolBoxRubbishContentEntity.java
================================================
package robot.AToolBox.entity;
import lombok.Data;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/4 17:42
*/
@Data
public class ToolBoxRubbishContentEntity {
private String name;
private String type;
}
================================================
FILE: src/main/java/robot/Ciba/CibaEveryDayHello.java
================================================
package robot.Ciba;
import com.alibaba.fastjson.JSON;
import config.GlobalConfig;
import robot.Ciba.entity.CibaEveryDayHelloEntity;
import utils.HttpRequestUtil;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/18 11:35
*/
public class CibaEveryDayHello {
private static final String CIBA_EVERYDAY = GlobalConfig.getValue("ciba.everydayHello", "");
public static String getCibaEveryday() {
String response = HttpRequestUtil.doGet(CIBA_EVERYDAY);
CibaEveryDayHelloEntity everyDayEntity = JSON.parseObject(response, CibaEveryDayHelloEntity.class);
return everyDayEntity == null ? null : everyDayEntity.getSentence();
}
}
================================================
FILE: src/main/java/robot/Ciba/entity/CibaEveryDayHelloEntity.java
================================================
package robot.Ciba.entity;
import cons.WxMsg;
import lombok.Data;
import java.util.List;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/18 11:36
*/
@Data
public class CibaEveryDayHelloEntity {
private String sid;
private String tts;
private String content;
private String note;
private String love;
private String translation;
private String picture;
private String picture2;
private String caption;
private String dateline;
private String s_pv;
private String sp_pv;
private List<CibaEveryDayHelloTags> tags;
private String fenxiang_img;
public String getSentence() {
return content + WxMsg.LINE
+ note + WxMsg.LINE;
}
}
@Data
class CibaEveryDayHelloTags {
private String id;
private String name;
}
================================================
FILE: src/main/java/robot/QingyunkeRobot/QingyunkeRobot.java
================================================
package robot.QingyunkeRobot;
import config.GlobalConfig;
import org.apache.commons.lang3.StringUtils;
import robot.QingyunkeRobot.entity.QingyunkeResponseEntity;
import com.alibaba.fastjson.JSON;
import utils.HttpRequestUtil;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
public class QingyunkeRobot {
private static final String ChatRobot = GlobalConfig.getValue("QingyunkeRobot.chat", "");
private static final String RECEIVE_CHAT_MSG_LINE = "{br}";
public static String getResponse(String keyWord) {
if (StringUtils.isBlank(keyWord)) {
return null;
}
String link = ChatRobot;
try {
link += URLEncoder.encode(keyWord, StandardCharsets.UTF_8.toString());
} catch (UnsupportedEncodingException e) {
link += keyWord;
}
String response = HttpRequestUtil.doGet(link);
if (StringUtils.isBlank(response)) {
return null;
}
QingyunkeResponseEntity qingResponse = JSON.parseObject(response, QingyunkeResponseEntity.class);
return replaceBr(qingResponse.getContent());
}
private static String replaceBr(String content) {
if (StringUtils.isBlank(content)) {
return null;
}
return content.replace(RECEIVE_CHAT_MSG_LINE, "\n");
}
}
================================================
FILE: src/main/java/robot/QingyunkeRobot/QingyunkeWeather/QingWeather.java
================================================
package robot.QingyunkeRobot.QingyunkeWeather;
import config.GlobalConfig;
import org.apache.commons.lang3.StringUtils;
import robot.QingyunkeRobot.QingyunkeWeather.entity.QingWeatherEntity;
import com.alibaba.fastjson.JSON;
import utils.HttpRequestUtil;
public class QingWeather {
private static final String QING_WEATHER = GlobalConfig.getValue("QingyunkeRobot.weather", "");
public static String getWeatherByCityId(String cityId) {
if (StringUtils.isBlank(cityId)) {
return null;
}
String response = HttpRequestUtil.doGet(QING_WEATHER + cityId);
if (StringUtils.isBlank(response)) {
return null;
}
QingWeatherEntity weather = JSON.parseObject(response, QingWeatherEntity.class);
return weather.isValid() ? weather.getWeather() : null;
}
public static String getWeatherByKeyword(String keyWord) {
if (StringUtils.isBlank(keyWord)) {
return null;
}
String cityName = keyWord.substring(0, keyWord.length() - 2);
return QingWeather.getWeatherByCityName(cityName);
}
public static String getWeatherByCityName(String cityName) {
if (StringUtils.isBlank(cityName)) {
return null;
}
// 部分地区有问题,已知的有:北京朝阳区和辽宁朝阳市;福田区;浦东新区
switch (cityName) {
case "朝阳市":
// 查天气时,朝阳默认为北京朝阳区;朝阳市为辽宁朝阳市
return QingWeather.getWeatherByCityId("101071201");
case "福田区":
case "福田":
return null;
case "浦东新区":
case "浦东":
return QingWeather.getWeatherByCityId("101021300");
case "帝都":
// 帝都默认为北京
return QingWeather.getWeatherByCityId("101010100");
case "魔都":
// 魔都默认为上海
return QingWeather.getWeatherByCityId("101020100");
case "长安":
// 长安默认为西安
return QingWeather.getWeatherByCityId("101110101");
}
if (cityName.endsWith("市") || cityName.endsWith("县") || cityName.endsWith("区")) {
cityName = cityName.substring(0, cityName.length() - 1);
}
String cityId = QingWeatherCityId.getInstance().getCityId(cityName);
return QingWeather.getWeatherByCityId(cityId);
}
}
================================================
FILE: src/main/java/robot/QingyunkeRobot/QingyunkeWeather/QingWeatherCityId.java
================================================
package robot.QingyunkeRobot.QingyunkeWeather;
import config.QingWeatherCityConfig;
import robot.QingyunkeRobot.QingyunkeWeather.entity.QingWeatherCityEntity;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class QingWeatherCityId {
private static volatile QingWeatherCityId INSTANCE;
private QingWeatherCityId() {
cityList = QingWeatherCityConfig.getInstance().getCityList();
}
public static QingWeatherCityId getInstance() {
if (INSTANCE == null) {
synchronized (QingWeatherCityConfig.class) {
if (INSTANCE == null) {
INSTANCE = new QingWeatherCityId();
}
}
}
return INSTANCE;
}
private List<QingWeatherCityEntity> cityList;
private Map<String, String> cityIdMap = new ConcurrentHashMap<>();
public String getCityId(String cityName) {
cityName = cityName.trim();
if (StringUtils.isBlank(cityName)) {
return null;
}
if (cityIdMap.containsKey(cityName)) {
return cityIdMap.get(cityName);
}
for (QingWeatherCityEntity cityEntity : cityList) {
if (cityEntity.getCity_name().equals(cityName) && StringUtils.isNotBlank(cityEntity.getCity_code())) {
cityIdMap.put(cityName, cityEntity.getCity_code());
return cityEntity.getCity_code();
}
}
return null;
}
}
================================================
FILE: src/main/java/robot/QingyunkeRobot/QingyunkeWeather/entity/QingWeatherCityEntity.java
================================================
package robot.QingyunkeRobot.QingyunkeWeather.entity;
import lombok.Data;
@Data
public class QingWeatherCityEntity {
private int _id;
private int id;
private int pid;
private String city_code;
private String city_name;
}
================================================
FILE: src/main/java/robot/QingyunkeRobot/QingyunkeWeather/entity/QingWeatherEntity.java
================================================
package robot.QingyunkeRobot.QingyunkeWeather.entity;
import cons.WxMsg;
import lombok.Data;
import java.util.List;
@Data
public class QingWeatherEntity {
private static final int SUCCESS = 200;
private String time;
private CityInfo cityInfo;
private String date;
private String message;
private int status;
private WeatherData data;
public boolean isValid() {
return status == SUCCESS;
}
public String getWeather() {
String today = date.substring(date.length() - 2);
for (OtherDay thisDay : data.getForecast()) {
if (thisDay.getDate().equals(today)) {
return cityInfo.getCityName() + " " + thisDay.getWeather();
}
}
return cityInfo.getCityName() + "今日天气:"
+ data.toString()
+ "更新时间" + time.substring(11) + WxMsg.LINE;
}
}
@Data
class CityInfo {
private String city;
private String cityID;
private String parent;
private String updateTime;
String getCityName() {
switch (city) {
case "北京市":
case "天津市":
case "重庆市":
case "上海市":
return city;
default:
return parent + city;
}
}
}
@Data
class WeatherData {
private String shidu;
private int pm25;
private int pm10;
private String quality;
private String wendu;
private String ganmao;
private OtherDay yesterday;
private List<OtherDay> forecast;
@Override
public String toString() {
return "温度:" + wendu + "℃" +
", 湿度:" + shidu +
", pm25:" + pm25 +
", pm10:" + pm10 +
", 空气质量:" + quality +
", " + ganmao + "。";
}
}
@Data
class OtherDay {
private String date;
private String sunrise;
private String high;
private String low;
private String sunset;
private int aqi;
private String ymd;
private String week;
private String fx;
private String fl;
private String type;
private String notice;
String getWeather() {
return ymd + " " + week + WxMsg.LINE
+ "【天气】 " + type + WxMsg.LINE
+ "【温度】 " + high + " ," + low + WxMsg.LINE
+ "【风力】 " + fx + " " + fl + WxMsg.LINE
+ "【提示】 " + notice + WxMsg.LINE;
}
}
================================================
FILE: src/main/java/robot/QingyunkeRobot/entity/QingyunkeResponseEntity.java
================================================
package robot.QingyunkeRobot.entity;
import org.apache.commons.lang3.StringUtils;
public class QingyunkeResponseEntity {
private int code;
private String content;
public boolean isValid(){
return code == 0 && StringUtils.isNotBlank(content);
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
================================================
FILE: src/main/java/robot/RollToolsApi/RollNews.java
================================================
package robot.RollToolsApi;
import cache.redis.NewsCacheFactory;
import cache.redis.entity.NewsCacheEntity;
import com.alibaba.fastjson.JSONObject;
import config.GlobalConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import robot.RollToolsApi.entity.RollNewsContentEntity;
import robot.RollToolsApi.entity.RollNewsEntity;
import utils.HttpRequestUtil;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/7 16:10
*/
@Slf4j
public class RollNews {
private static final String NEWS_LIST_LINK = GlobalConfig.getValue("RollToolsApi.host", "") + GlobalConfig.getValue("RollToolsApi.news.list", "");
// private static final String NEWS_DETAILS_LINK = GlobalConfig.getValue("RollToolsApi.host", "") + GlobalConfig.getValue("RollToolsApi.news.details", "");
// private static Map<String, List<RollNewsContentEntity>> TodayNews = new ConcurrentHashMap<>();
public static String getTodayTotalNews(String typeId, int limit) {
NewsCacheEntity newsCacheEntity = NewsCacheFactory.getNewsCacheEntity(typeId,limit);
String todayNews = newsCacheEntity.get();
if (todayNews != null) {
return todayNews;
}
String link = NEWS_LIST_LINK + typeId;
String response = HttpRequestUtil.doGet(link);
if (StringUtils.isBlank(response)) {
return null;
}
RollNewsEntity rollNewsEntity = JSONObject.parseObject(response, RollNewsEntity.class);
if (rollNewsEntity.isInValid()) {
return null;
}
String result = rollNewsEntity.getTodayNews(limit);
newsCacheEntity.setValue(result).save();
// TodayNews.put(typeId, rollNewsEntity.getData());
return result;
}
// 好像没必要做一个查看新闻详情的功能。只要实现一个每日新闻速览就可以了(只展示梗概)
// 如果有需求做一个查看新闻详情的功能,可以吧这些注释掉的代码取消注释,然后自己完善一下就可以了
// public static String getToadyNewsByIndex(String typeId, String newsIndex) {
// int index = Integer.valueOf(newsIndex) - 1;
// RollNewsContentEntity rollNewsContentEntity = TodayNews.get(typeId).get(index);
// String newsId = rollNewsContentEntity.getNewsId();
// return getNewsById( newsId);
// }
//
// private static String getNewsById(String newsId) {
// NewsCacheEntity singleNewsCacheEntity = NewsCacheFactory.getSingleZhihuHotCacheEntity(newsId);
// String single = singleNewsCacheEntity.get();
// if (StringUtils.isNotBlank(single)){
// return single;
// }
// String url = NEWS_DETAILS_LINK + newsId;
// String response = HttpRequestUtil.doGet(url);
// if (StringUtils.isBlank(response)) {
// return null;
// // TODO
// }
}
================================================
FILE: src/main/java/robot/RollToolsApi/RollWeather.java
================================================
package robot.RollToolsApi;
import config.GlobalConfig;
import org.apache.commons.lang3.StringUtils;
import robot.RollToolsApi.entity.RollWeatherEntity;
import com.alibaba.fastjson.JSON;
import utils.HttpRequestUtil;
public class RollWeather {
private static final String ROLL_CURRENT_WEATHER = GlobalConfig.getValue("RollToolsApi.host", "") + GlobalConfig.getValue("RollToolsApi.weather.current", "");
public static String getWeatherByKeyword(String keyword) {
if (StringUtils.isBlank(keyword)) {
return null;
}
String cityName = keyword.startsWith("天气") ?
keyword.substring(2) : keyword.substring(0, keyword.length() - 2);
return RollWeather.getWeatherByCityName(cityName);
}
public static String getWeatherByCityName(String cityName) {
if (StringUtils.isBlank(cityName)) {
return null;
}
String response = HttpRequestUtil.doGet(ROLL_CURRENT_WEATHER + cityName);
if (StringUtils.isBlank(response)) {
return null;
}
RollWeatherEntity weather = JSON.parseObject(response, RollWeatherEntity.class);
return weather == null ? null : weather.getWeatherDefaultNull();
}
}
================================================
FILE: src/main/java/robot/RollToolsApi/entity/RollNewsContentEntity.java
================================================
package robot.RollToolsApi.entity;
import lombok.Data;
import java.util.List;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/7 17:24
*/
@Data
public class RollNewsContentEntity {
private String title;
private List<String> imgList;
private String source;
private String newsId;
private String digest;
private String postTime;
private List<String> videoList;
}
================================================
FILE: src/main/java/robot/RollToolsApi/entity/RollNewsDetailsEntity.java
================================================
package robot.RollToolsApi.entity;
import lombok.Data;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/7 17:52
*/
@Data
public class RollNewsDetailsEntity {
private static final int SUCCESS_CODE = 1;
}
================================================
FILE: src/main/java/robot/RollToolsApi/entity/RollNewsEntity.java
================================================
package robot.RollToolsApi.entity;
import IdentifyCommand.PreProcessMessage;
import config.GlobalConfig;
import cons.WxMsg;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import javax.swing.border.TitledBorder;
import java.util.List;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/7 16:10
*/
@Data
public class RollNewsEntity {
private static final int DEFAULT_NEWS_SIZE = Integer.valueOf(GlobalConfig.getValue("RollToolsApi.news.list.size", "5"));
private static final int SUCCESS_CODE = 1;
private int code;
private String msg;
private List<RollNewsContentEntity> data;
public boolean isInValid() {
return SUCCESS_CODE != code || data == null || data.isEmpty();
}
public String getTodayNews() {
return getTodayNews(Math.max(DEFAULT_NEWS_SIZE, 0));
}
public String getTodayNews(int maxSize) {
if (isInValid()) {
return null;
}
int length = data.size() > maxSize ? maxSize : data.size();
StringBuilder result = new StringBuilder();
for (int i = 0; i < length; i++) {
RollNewsContentEntity rollNewsContentEntity = data.get(i);
result.append(i + 1).append(". ")
.append(rollNewsContentEntity.getTitle())
.append("(").append(rollNewsContentEntity.getSource()).append(")")
.append(WxMsg.LINE);
}
return result.toString();
}
}
================================================
FILE: src/main/java/robot/RollToolsApi/entity/RollWeatherEntity.java
================================================
package robot.RollToolsApi.entity;
import cons.WxMsg;
import lombok.Data;
@Data
public class RollWeatherEntity {
private static final int SUCCESS = 1;
private int code;
private String msg;
private RollWeatherData data;
public boolean isValid() {
return code == SUCCESS;
}
public String getWeather() {
return data.toString();
}
public String getWeatherDefaultNull() {
return isValid() ? data.toString() : null;
}
}
@Data
class RollWeatherData {
private String address;
private String cityCode;
private String temp;
private String weather;
private String windDirection;
private String windPower;
private String humidity;
private String reportTime;
@Override
public String toString() {
return address + WxMsg.LINE
+ "【天气】 " + weather + WxMsg.LINE
+ "【温度】" + temp + WxMsg.LINE
+ "【湿度】" + humidity + WxMsg.LINE
+ "【风力】" + windDirection + "风 " + windPower + WxMsg.LINE
+ "【更新时间】" + reportTime + WxMsg.LINE;
}
}
================================================
FILE: src/main/java/robot/RubbishClassificationApp/RubbishApp.java
================================================
package robot.RubbishClassificationApp;
import config.GlobalConfig;
import enums.RubbishType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import utils.HttpRequestUtil;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/1 21:51
*/
@Slf4j
public class RubbishApp {
private static final String LA_JI_FEN_LEI_APP = GlobalConfig.getValue("rubbish.LaJjFenLeiAPP", "");
public static RubbishType getRubbishType(String rubbish) {
if (StringUtils.isBlank(rubbish)) {
return null;
}
String link = LA_JI_FEN_LEI_APP + rubbish;
String response = HttpRequestUtil.doGet(link);
log.info("RubbishApp::getRubbishType, httpRequest >> rubbish: {}, response: {}", rubbish, response);
RubbishType rubbishType;
if (StringUtils.isBlank(response)) {
rubbishType = RubbishType.NO_RESPONSE;
} else if (response.contains("干垃圾是指")) {
rubbishType = RubbishType.RESIDUAL_WASTE;
} else if (response.contains("湿垃圾是指")) {
rubbishType = RubbishType.HOUSEHOLD_FOOD_WASTE;
} else if (response.contains("有害垃圾是指")) {
rubbishType = RubbishType.HAZARDOUS_WASTE;
} else if (response.contains("可回收物是指")) {
return RubbishType.RECYCLABLE_WASTE;
} else {
rubbishType = RubbishType.NOT_EXISTS;
}
log.info("RubbishApp::getRubbishType, httpRequest >> rubbish: {}, result: {}", rubbish, rubbishType);
return rubbishType;
}
}
================================================
FILE: src/main/java/robot/Zhihu/ZhihuHot.java
================================================
package robot.Zhihu;
import IdentifyCommand.PreProcessMessage;
import cache.redis.ZhihuHotCacheFactory;
import cache.redis.entity.ZhihuHotCacheEntity;
import com.alibaba.fastjson.JSONObject;
import config.GlobalConfig;
import config.RedisConfig;
import cons.WxMsg;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import robot.Zhihu.entity.ZhihuHotContentEntity;
import robot.Zhihu.entity.ZhihuHotDetailEntity;
import robot.Zhihu.entity.ZhihuHotEntity;
import utils.HttpRequestUtil;
import java.util.ArrayList;
import java.util.List;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/7 18:53
*/
@Slf4j
public class ZhihuHot {
private static final String ZHIHU_HOT_LINK = GlobalConfig.getValue("Zhihu.hot", "");
private static final int ZHIHU_HOT_LIMIT = Integer.valueOf(GlobalConfig.getValue("Zhihu.hot.limit", "9"));
private static List<ZhihuHotContentEntity> CONTENT = new ArrayList<>(0);
public static String getZhihuHot() {
if (RedisConfig.isRedisNotEnable()) {
return null;
}
ZhihuHotCacheEntity zhihuHotCacheEntity = ZhihuHotCacheFactory.getZhihuHotCacheEntity(ZHIHU_HOT_LIMIT);
String cache = zhihuHotCacheEntity.get();
if (cache != null) {
return cache;
}
String response = HttpRequestUtil.doGet(ZHIHU_HOT_LINK);
if (StringUtils.isBlank(response)) {
return null;
}
ZhihuHotEntity zhihuHotEntity = JSONObject.parseObject(response, ZhihuHotEntity.class);
if (zhihuHotEntity == null) {
return null;
}
CONTENT = zhihuHotEntity.getRecent();
String content = zhihuHotEntity.getContent(ZHIHU_HOT_LIMIT);
if (StringUtils.isNotBlank(content)) {
content = "每日知乎热榜:" + WxMsg.LINE
+ content
+ "查看详情请发送>> " + PreProcessMessage.getCommandPrefix() + "知乎" + " + 序号";
}
zhihuHotCacheEntity.setValue(content).save();
return content;
}
public static String getSingleZhihuHot(int index) {
if (RedisConfig.isRedisNotEnable()) {
return null;
}
if (CONTENT == null || CONTENT.size() <= index || index < 0) {
log.info("getSingleZhihuHot, CONTENT:{}, index: {},return: null", CONTENT == null ? null : CONTENT.size(), index);
return null;
}
ZhihuHotContentEntity entity = CONTENT.get(index);
ZhihuHotCacheEntity singleZhihuHotCacheEntity = ZhihuHotCacheFactory.getSingleZhihuHotCacheEntity(entity.getNews_id());
String result = singleZhihuHotCacheEntity.get();
if (result != null) {
return result;
}
String url = entity.getUrl();
String response = HttpRequestUtil.doGet(url);
if (response == null) {
return null;
}
ZhihuHotDetailEntity zhihuHotDetailEntity = JSONObject.parseObject(response, ZhihuHotDetailEntity.class);
if (zhihuHotDetailEntity == null || zhihuHotDetailEntity.getShare_url() == null) {
return null;
}
result = zhihuHotDetailEntity.getResult();
singleZhihuHotCacheEntity.setValue(result).save();
return result;
}
}
================================================
FILE: src/main/java/robot/Zhihu/entity/ZhihuHotContentEntity.java
================================================
package robot.Zhihu.entity;
import lombok.Data;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/7 19:27
*/
@Data
public class ZhihuHotContentEntity {
private long news_id;
private String url;
private String thumbnail;
private String title;
}
================================================
FILE: src/main/java/robot/Zhihu/entity/ZhihuHotDetailEntity.java
================================================
package robot.Zhihu.entity;
import cons.WxMsg;
import lombok.Data;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/7 19:34
*/
@Data
public class ZhihuHotDetailEntity {
private String body;
private String image_source;
private String title;
private String image;
private String share_url;
private String thumbnail;
private String ga_prefix;
private long id;
public String getResult() {
return "【知乎热榜】" + title + WxMsg.LINE
+ "【查看详情】" + share_url + WxMsg.LINE;
}
}
================================================
FILE: src/main/java/robot/Zhihu/entity/ZhihuHotEntity.java
================================================
package robot.Zhihu.entity;
import cons.WxMsg;
import lombok.Data;
import java.util.List;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/7/7 18:54
*/
@Data
public class ZhihuHotEntity {
private List<ZhihuHotContentEntity> recent;
private boolean isValid() {
return recent != null && !recent.isEmpty();
}
public String getContent(int limit) {
if (!isValid() && limit <= 0) {
return "";
}
int length = Math.min(limit, recent.size());
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
ZhihuHotContentEntity zhihuHotContent = recent.get(i);
sb.append(i + 1).append(". ")
.append(zhihuHotContent.getTitle())
.append(WxMsg.LINE);
}
return sb.toString();
}
}
================================================
FILE: src/main/java/schedule/EverydayHelloSchedule.java
================================================
package schedule;
import config.GlobalConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import schedule.task.GroupEverydayTask;
import utils.DateUtil;
import utils.ScheduleUtil;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/29 15:01
*/
@Slf4j
public class EverydayHelloSchedule {
private static final int MILLE_SECONDS_PER_MINUTE = 60 * 1000;
private static final int MILLE_SECONDS_PER_HOUR = 60 * MILLE_SECONDS_PER_MINUTE;
private static final int MILLE_SECONDS_PER_DAY = 24 * MILLE_SECONDS_PER_HOUR;
private static final boolean ENABLE =
GlobalConfig.getValue("everydayHello.enable", "false").equalsIgnoreCase("true");
private static String GROUP_TIME = GlobalConfig.getValue("everydayHello.group.time", "").trim();
private static long GROUP_PERIOD = MILLE_SECONDS_PER_DAY;
static {
if (StringUtils.isBlank(GROUP_TIME) || GROUP_TIME.length() != 6) {
log.info("每日一句定时调度,配置everydayHello.group.time失效,设为默认值083000.");
GROUP_TIME = "083000";
}
final String GROUP_PERIOD_CONFIG = GlobalConfig.getValue("everydayHello.group.period.hour", "").trim();
if (StringUtils.isNotBlank(GROUP_PERIOD_CONFIG)) {
try {
GROUP_PERIOD = Long.parseLong(GROUP_PERIOD_CONFIG) * MILLE_SECONDS_PER_HOUR;
// 调试用,以分钟为单位
// GROUP_PERIOD = Long.parseLong(GROUP_PERIOD_CONFIG) * 60 * 1000;
} catch (NumberFormatException e) {
log.error("startEverydaySchedule解析period失败。GROUP_PERIOD_CONFIG: {}", GROUP_PERIOD_CONFIG);
}
}
}
public static void startGroupEverydaySchedule() {
if (!ENABLE) {
log.info("startGroupEverydaySchedule, 配置为不启用群聊发送每日一句定时调度。");
return;
}
try {
Date curDate = new Date();
String curTime = DateUtil.getFormatDate(curDate, "HHmmss");
Date scheduleDate =
DateUtil.parseDate(DateUtil.getFormatDate(curDate, "yyyyMMdd") + GROUP_TIME, "yyyyMMddHHmmss");
if (scheduleDate == null) {
log.error("解析scheduleDate为空,调度失败。");
return;
}
if (curTime != null && GROUP_TIME.compareTo(curTime) <= 0) {
scheduleDate = DateUtil.addOneDay(scheduleDate);
}
long initialDelay = Math.max(0, scheduleDate.getTime() - System.currentTimeMillis());
log.info("EverydayHelloSchedule::startGroupEverydaySchedule, schedule >> scheduleDate: {}, period: {}分钟",
DateUtil.getViewDate(scheduleDate), GROUP_PERIOD / MILLE_SECONDS_PER_MINUTE);
ScheduleUtil
.scheduleAtFixedRate(new GroupEverydayTask(), initialDelay, GROUP_PERIOD, TimeUnit.MILLISECONDS);
} catch (Exception e) {
log.error("startGroupEverydaySchedule error, ", e);
}
}
}
================================================
FILE: src/main/java/schedule/base/BaseScheduleTask.java
================================================
package schedule.base;
import org.apache.commons.lang3.time.StopWatch;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import utils.DateUtil;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/9/8 10:43
*/
@Slf4j
@NoArgsConstructor
@AllArgsConstructor
public abstract class BaseScheduleTask implements Runnable {
@Getter
private String taskName;
@Override
public void run() {
log.info("scheduleTask, taskName: [{}], now is: [{}]", taskName, DateUtil.getCurViewDate());
StopWatch stopWatch = new StopWatch();
try {
process();
} catch (Exception e) {
log.error("scheduleTask error, taskName: [{}], ", taskName, e);
} finally {
stopWatch.stop();
log.info("scheduleTask finished, taskName: [{}], cost: [{}] mille seconds.", taskName, stopWatch.getTime());
}
}
protected abstract void process();
}
================================================
FILE: src/main/java/schedule/task/FriendEverydayTask.java
================================================
package schedule.task;
import org.apache.commons.lang3.StringUtils;
import api.EveryDayHelloApi;
import lombok.extern.slf4j.Slf4j;
import main.WechatBotClient;
import main.service.everydayHelloMsg.EveryDayHelloWhiteList;
import schedule.base.BaseScheduleTask;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/9/18 11:17
*/
@Slf4j
public class FriendEverydayTask extends BaseScheduleTask {
public FriendEverydayTask() {
super("friendEverydayTask");
}
public void process() {
String msg = EveryDayHelloApi.getFriendHelloMsg();
log.info("friendEverydayHelloMsg, msg: {}", msg);
if (StringUtils.isNotBlank(msg)) {
EveryDayHelloWhiteList.getInstance().getFriendSet().forEach(friend -> {
WechatBotClient.getWeChatClient().sendText(friend, msg);
log.info("SendFriendEverydayHelloMsg, friend: {}", friend.name);
});
}
log.info("Finish SendFriendEverydayHelloMsg.");
}
}
================================================
FILE: src/main/java/schedule/task/GroupEverydayTask.java
================================================
package schedule.task;
import org.apache.commons.lang3.StringUtils;
import api.EveryDayHelloApi;
import lombok.extern.slf4j.Slf4j;
import main.WechatBotClient;
import main.service.everydayHelloMsg.EveryDayHelloWhiteList;
import schedule.base.BaseScheduleTask;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/9/8 10:52
*/
@Slf4j
public class GroupEverydayTask extends BaseScheduleTask {
public GroupEverydayTask() {
super("GroupEverydayTask");
}
public void process() {
String msg = EveryDayHelloApi.getGroupHelloMsg();
log.info("GroupEverydayHelloMsg msg: {}", msg);
if (StringUtils.isNotBlank(msg)) {
EveryDayHelloWhiteList.getInstance().getGroupSet().forEach(group -> {
log.info("SendGroupEverydayHelloMsg, group: {}", group.name);
WechatBotClient.getWeChatClient().sendText(group, msg);
});
}
log.info("Finish SendGroupEverydayHelloMsg.");
}
}
================================================
FILE: src/main/java/utils/AtMeMsg.java
================================================
package utils;
import cons.WxMsg;
import me.xuxiaoxiao.chatapi.wechat.entity.contact.WXGroup;
import me.xuxiaoxiao.chatapi.wechat.entity.message.WXMessage;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/18 20:34
*/
public class AtMeMsg {
private static final Logger log = LoggerFactory.getLogger(AtMeMsg.class);
private static final Map<String, String> MY_DISPLAY_OR_NICKNAME = new ConcurrentHashMap<>();
/**
* 判定群文字消息是否是at自己的
*
* @param message
* @return
*/
public static boolean isAtMe(WXMessage message) {
return message.content.contains(atMeFix(message));
}
private static String atMeFix(WXMessage message) {
if (MY_DISPLAY_OR_NICKNAME.containsKey(message.fromGroup.name)) {
return MY_DISPLAY_OR_NICKNAME.get(message.fromGroup.name);
}
String myName = message.toContact.name;
HashMap<String, WXGroup.Member> members = message.fromGroup.members;
for (HashMap.Entry<String, WXGroup.Member> entry : members.entrySet()) {
if (myName.equals(entry.getValue().name)) {
if (StringUtils.isNotBlank(entry.getValue().display)) {
myName = entry.getValue().display;
}
break;
}
}
String atMeFix = "@" + myName + WxMsg.AT_ME_SPACE;
MY_DISPLAY_OR_NICKNAME.put(message.fromGroup.name, atMeFix);
return atMeFix;
}
}
================================================
FILE: src/main/java/utils/DateUtil.java
================================================
package utils;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/19 18:21
*/
public class DateUtil {
private static final int MILLE_SECONDS_PER_DAY = 24 * 60 * 60 * 1000;
private static final String YYMMDDHHMMSS = "yyyyMMddHHmmss";
public static Date addOneDay(Date oldDate) {
return addDate(oldDate, 1);
}
public static Date addDate(Date oldDate, int addDays) {
long time = oldDate.getTime();
long addTime = MILLE_SECONDS_PER_DAY * (long) addDays;
time += addTime;
return new Date(time);
}
public static String getYYMMDDHHMMSSDate(Date date) {
try {
SimpleDateFormat targetformator = new SimpleDateFormat(YYMMDDHHMMSS);
return targetformator.format(date);
} catch (Exception e) {
return null;
}
}
public static String getCurViewDate() {
return getViewDate(new Date());
}
public static String getViewDate(Date date) {
try {
SimpleDateFormat targetformator = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return targetformator.format(date);
} catch (Exception e) {
return null;
}
}
public static String getCacheFormatDate(Date date) {
try {
SimpleDateFormat targetformator = new SimpleDateFormat("yyyyMMdd");
return targetformator.format(date);
} catch (Exception e) {
return null;
}
}
public static String getFormatDate(Date date, String pattern) {
try {
SimpleDateFormat targetformator = new SimpleDateFormat(pattern);
return targetformator.format(date);
} catch (Exception e) {
return null;
}
}
public static Date parseDate(String source, String pattern) {
SimpleDateFormat formater = new SimpleDateFormat(pattern);
try {
return formater.parse(source);
} catch (Exception e) {
return null;
}
}
}
================================================
FILE: src/main/java/utils/GroupMsgUtil.java
================================================
package utils;
import me.xuxiaoxiao.chatapi.wechat.entity.message.WXMessage;
import org.apache.commons.lang3.StringUtils;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/20 17:36
*/
public class GroupMsgUtil {
public static String getUserDisplayOrName(WXMessage message) {
String display = message.fromGroup.members.containsKey(message.fromUser.id)
? message.fromGroup.members.get(message.fromUser.id).display : null;
return StringUtils.isBlank(display) ? message.fromUser.name : display.trim();
}
}
================================================
FILE: src/main/java/utils/HttpRequestUtil.java
================================================
package utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
@Slf4j
public class HttpRequestUtil {
public static String doGet(String url) {
if (StringUtils.isBlank(url)) {
return null;
}
log.info("HttpRequestUtil::doGet, url: {}", url);
return httpRequest(url, "GET");
}
private static String httpRequest(String requestUrl, String method) {
StringBuilder buffer = new StringBuilder();
try {
URL url = new URL(requestUrl);
HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();
httpUrlConn.setDoInput(true);
httpUrlConn.setRequestMethod(method);
httpUrlConn.connect();
InputStream inputStream = httpUrlConn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
httpUrlConn.disconnect();
} catch (Exception e) {
log.error("HttpRequestUtil::httpRequest error, requestUrl: {}", requestUrl, e);
}
return buffer.toString();
}
}
================================================
FILE: src/main/java/utils/QRCodeUtil.java
================================================
package utils;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/6/29 17:57
*/
public class QRCodeUtil {
private static final String LINE = "\n";
public static String printQRCode(String url) {
// todo
return LINE + "" + LINE;
}
}
================================================
FILE: src/main/java/utils/ScheduleUtil.java
================================================
package utils;
import java.util.concurrent.TimeUnit;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import schedule.base.BaseScheduleTask;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/9/8 11:02
*/
@Slf4j
public class ScheduleUtil {
public static void scheduleAtFixedRate(@NonNull BaseScheduleTask task,
long initialDelay, long period, TimeUnit timeUnit) {
if (initialDelay < 0) {
throw new IllegalArgumentException("initialDelay should not be smaller than zero!");
}
if (period <= 0) {
throw new IllegalArgumentException("period should be bigger than zero!");
}
try {
log.info(
"ScheduleUtil.scheduleAtFixedRate, now is [{}], "
+ "taskName: [{}], initialDelay: [{}], period: [{}], timeUnit: [{}]",
DateUtil.getCurViewDate(), task.getTaskName(), initialDelay, period, timeUnit);
ThreadPoolUtil.getSchedulePool().scheduleAtFixedRate(task, initialDelay, period, timeUnit);
} catch (Exception e) {
log.error("ScheduleUtil.scheduleAtFixedRate error, taskName: [{}], ", task.getTaskName(), e);
}
}
}
================================================
FILE: src/main/java/utils/ThreadPoolUtil.java
================================================
package utils;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.*;
/**
* Created by IntelliJ IDEA.
*
* @author Javior
* @date 2019/9/7 13:03
*/
@Slf4j
public class ThreadPoolUtil {
private static volatile ThreadPoolExecutor cachedPool;
private static volatile ScheduledThreadPoolExecutor schedulePool;
public static ThreadPoolExecutor getCachedPool() {
if (cachedPool == null) {
synchronized (ThreadPoolUtil.class) {
if (cachedPool == null) {
cachedPool = new ThreadPoolExecutor(0,
200,
60,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
}
}
}
return cachedPool;
}
public static ScheduledThreadPoolExecutor getSchedulePool() {
if (schedulePool == null) {
synchronized (ThreadPoolUtil.class) {
if (schedulePool == null) {
schedulePool = new ScheduledThreadPoolExecutor(100, new ThreadPoolExecutor.CallerRunsPolicy());
}
}
}
return schedulePool;
}
}
================================================
FILE: src/main/resources/city.json
================================================
[
{
"_id": 1,
"id": 1,
"pid": 0,
"city_code": "101010100",
"city_name": "北京"
},
{
"_id": 2,
"id": 2,
"pid": 0,
"city_code": "",
"city_name": "安徽"
},
{
"_id": 3,
"id": 3,
"pid": 0,
"city_code": "",
"city_name": "福建"
},
{
"_id": 4,
"id": 4,
"pid": 0,
"city_code": "",
"city_name": "甘肃"
},
{
"_id": 5,
"id": 5,
"pid": 0,
"city_code": "",
"city_name": "广东"
},
{
"_id": 6,
"id": 6,
"pid": 0,
"city_code": "",
"city_name": "广西"
},
{
"_id": 7,
"id": 7,
"pid": 0,
"city_code": "",
"city_name": "贵州"
},
{
"_id": 8,
"id": 8,
"pid": 0,
"city_code": "",
"city_name": "海南"
},
{
"_id": 9,
"id": 9,
"pid": 0,
"city_code": "",
"city_name": "河北"
},
{
"_id": 10,
"id": 10,
"pid": 0,
"city_code": "",
"city_name": "河南"
},
{
"_id": 11,
"id": 11,
"pid": 0,
"city_code": "",
"city_name": "黑龙江"
},
{
"_id": 12,
"id": 12,
"pid": 0,
"city_code": "",
"city_name": "湖北"
},
{
"_id": 13,
"id": 13,
"pid": 0,
"city_code": "",
"city_name": "湖南"
},
{
"_id": 14,
"id": 14,
"pid": 0,
"city_code": "",
"city_name": "吉林"
},
{
"_id": 15,
"id": 15,
"pid": 0,
"city_code": "",
"city_name": "江苏"
},
{
"_id": 16,
"id": 16,
"pid": 0,
"city_code": "",
"city_name": "江西"
},
{
"_id": 17,
"id": 17,
"pid": 0,
"city_code": "",
"city_name": "辽宁"
},
{
"_id": 18,
"id": 18,
"pid": 0,
"city_code": "",
"city_name": "内蒙古"
},
{
"_id": 19,
"id": 19,
"pid": 0,
"city_code": "",
"city_name": "宁夏"
},
{
"_id": 20,
"id": 20,
"pid": 0,
"city_code": "",
"city_name": "青海"
},
{
"_id": 21,
"id": 21,
"pid": 0,
"city_code": "",
"city_name": "山东"
},
{
"_id": 22,
"id": 22,
"pid": 0,
"city_code": "",
"city_name": "山西"
},
{
"_id": 23,
"id": 23,
"pid": 0,
"city_code": "",
"city_name": "陕西"
},
{
"_id": 24,
"id": 24,
"pid": 0,
"city_code": "101020100",
"city_name": "上海"
},
{
"_id": 25,
"id": 25,
"pid": 0,
"city_code": "",
"city_name": "四川"
},
{
"_id": 26,
"id": 26,
"pid": 0,
"city_code": "101030100",
"city_name": "天津"
},
{
"_id": 27,
"id": 27,
"pid": 0,
"city_code": "",
"city_name": "西藏"
},
{
"_id": 28,
"id": 28,
"pid": 0,
"city_code": "",
"city_name": "新疆"
},
{
"_id": 29,
"id": 29,
"pid": 0,
"city_code": "",
"city_name": "云南"
},
{
"_id": 30,
"id": 30,
"pid": 0,
"city_code": "",
"city_name": "浙江"
},
{
"_id": 31,
"id": 31,
"pid": 0,
"city_code": "101040100",
"city_name": "重庆"
},
{
"_id": 32,
"id": 32,
"pid": 0,
"city_code": "101320101",
"city_name": "香港"
},
{
"_id": 33,
"id": 33,
"pid": 0,
"city_code": "101330101",
"city_name": "澳门"
},
{
"_id": 34,
"id": 34,
"pid": 0,
"city_code": "",
"city_name": "台湾"
},
{
"_id": 35,
"id": 35,
"pid": 2,
"city_code": "101220601",
"city_name": "安庆"
},
{
"_id": 36,
"id": 36,
"pid": 2,
"city_code": "101220201",
"city_name": "蚌埠"
},
{
"_id": 37,
"id": 37,
"pid": 3400,
"city_code": "101220105",
"city_name": "巢湖"
},
{
"_id": 38,
"id": 38,
"pid": 2,
"city_code": "101221701",
"city_name": "池州"
},
{
"_id": 39,
"id": 39,
"pid": 2,
"city_code": "101221101",
"city_name": "滁州"
},
{
"_id": 40,
"id": 40,
"pid": 2,
"city_code": "101220801",
"city_name": "阜阳"
},
{
"_id": 41,
"id": 41,
"pid": 2,
"city_code": "101221201",
"city_name": "淮北"
},
{
"_id": 42,
"id": 42,
"pid": 2,
"city_code": "101220401",
"city_name": "淮南"
},
{
"_id": 43,
"id": 43,
"pid": 2,
"city_code": "101221001",
"city_name": "黄山"
},
{
"_id": 44,
"id": 44,
"pid": 2,
"city_code": "101221501",
"city_name": "六安"
},
{
"_id": 45,
"id": 45,
"pid": 2,
"city_code": "101220501",
"city_name": "马鞍山"
},
{
"_id": 46,
"id": 46,
"pid": 2,
"city_code": "101220701",
"city_name": "宿州"
},
{
"_id": 47,
"id": 47,
"pid": 2,
"city_code": "101221301",
"city_name": "铜陵"
},
{
"_id": 48,
"id": 48,
"pid": 2,
"city_code": "101220301",
"city_name": "芜湖"
},
{
"_id": 49,
"id": 49,
"pid": 2,
"city_code": "101221401",
"city_name": "宣城"
},
{
"_id": 50,
"id": 50,
"pid": 2,
"city_code": "101220901",
"city_name": "亳州"
},
{
"_id": 51,
"id": 52,
"pid": 3,
"city_code": "101230101",
"city_name": "福州"
},
{
"_id": 52,
"id": 53,
"pid": 3,
"city_code": "101230701",
"city_name": "龙岩"
},
{
"_id": 53,
"id": 54,
"pid": 3,
"city_code": "101230901",
"city_name": "南平"
},
{
"_id": 54,
"id": 55,
"pid": 3,
"city_code": "101230301",
"city_name": "宁德"
},
{
"_id": 55,
"id": 56,
"pid": 3,
"city_code": "101230401",
"city_name": "莆田"
},
{
"_id": 56,
"id": 57,
"pid": 3,
"city_code": "101230501",
"city_name": "泉州"
},
{
"_id": 57,
"id": 58,
"pid": 3,
"city_code": "101230801",
"city_name": "三明"
},
{
"_id": 58,
"id": 59,
"pid": 3,
"city_code": "101230201",
"city_name": "厦门"
},
{
"_id": 59,
"id": 60,
"pid": 3,
"city_code": "101230601",
"city_name": "漳州"
},
{
"_id": 60,
"id": 61,
"pid": 4,
"city_code": "101160101",
"city_name": "兰州"
},
{
"_id": 61,
"id": 62,
"pid": 4,
"city_code": "101161301",
"city_name": "白银"
},
{
"_id": 62,
"id": 63,
"pid": 4,
"city_code": "101160201",
"city_name": "定西"
},
{
"_id": 63,
"id": 64,
"pid": 4,
"city_code": "",
"city_name": "甘南州"
},
{
"_id": 64,
"id": 65,
"pid": 4,
"city_code": "101161401",
"city_name": "嘉峪关"
},
{
"_id": 65,
"id": 66,
"pid": 4,
"city_code": "101160601",
"city_name": "金昌"
},
{
"_id": 66,
"id": 67,
"pid": 4,
"city_code": "101160801",
"city_name": "酒泉"
},
{
"_id": 67,
"id": 68,
"pid": 4,
"city_code": "101161101",
"city_name": "临夏"
},
{
"_id": 68,
"id": 69,
"pid": 4,
"city_code": "101161010",
"city_name": "陇南"
},
{
"_id": 69,
"id": 70,
"pid": 4,
"city_code": "101160301",
"city_name": "平凉"
},
{
"_id": 70,
"id": 71,
"pid": 4,
"city_code": "101160401",
"city_name": "庆阳"
},
{
"_id": 71,
"id": 72,
"pid": 4,
"city_code": "101160901",
"city_name": "天水"
},
{
"_id": 72,
"id": 73,
"pid": 4,
"city_code": "101160501",
"city_name": "武威"
},
{
"_id": 73,
"id": 74,
"pid": 4,
"city_code": "101160701",
"city_name": "张掖"
},
{
"_id": 74,
"id": 75,
"pid": 5,
"city_code": "101280101",
"city_name": "广州"
},
{
"_id": 75,
"id": 76,
"pid": 5,
"city_code": "101280601",
"city_name": "深圳"
},
{
"_id": 76,
"id": 77,
"pid": 5,
"city_code": "101281501",
"city_name": "潮州"
},
{
"_id": 77,
"id": 78,
"pid": 5,
"city_code": "101281601",
"city_name": "东莞"
},
{
"_id": 78,
"id": 79,
"pid": 5,
"city_code": "101280800",
"city_name": "佛山"
},
{
"_id": 79,
"id": 80,
"pid": 5,
"city_code": "101281201",
"city_name": "河源"
},
{
"_id": 80,
"id": 81,
"pid": 5,
"city_code": "101280301",
"city_name": "惠州"
},
{
"_id": 81,
"id": 82,
"pid": 5,
"city_code": "101281101",
"city_name": "江门"
},
{
"_id": 82,
"id": 83,
"pid": 5,
"city_code": "101281901",
"city_name": "揭阳"
},
{
"_id": 83,
"id": 84,
"pid": 5,
"city_code": "101282001",
"city_name": "茂名"
},
{
"_id": 84,
"id": 85,
"pid": 5,
"city_code": "101280401",
"city_name": "梅州"
},
{
"_id": 85,
"id": 86,
"pid": 5,
"city_code": "101281301",
"city_name": "清远"
},
{
"_id": 86,
"id": 87,
"pid": 5,
"city_code": "101280501",
"city_name": "汕头"
},
{
"_id": 87,
"id": 88,
"pid": 5,
"city_code": "101282101",
"city_name": "汕尾"
},
{
"_id": 88,
"id": 89,
"pid": 5,
"city_code": "101280201",
"city_name": "韶关"
},
{
"_id": 89,
"id": 90,
"pid": 5,
"city_code": "101281801",
"city_name": "阳江"
},
{
"_id": 90,
"id": 91,
"pid": 5,
"city_code": "101281401",
"city_name": "云浮"
},
{
"_id": 91,
"id": 92,
"pid": 5,
"city_code": "101281001",
"city_name": "湛江"
},
{
"_id": 92,
"id": 93,
"pid": 5,
"city_code": "101280901",
"city_name": "肇庆"
},
{
"_id": 93,
"id": 94,
"pid": 5,
"city_code": "101281701",
"city_name": "中山"
},
{
"_id": 94,
"id": 95,
"pid": 5,
"city_code": "101280701",
"city_name": "珠海"
},
{
"_id": 95,
"id": 96,
"pid": 6,
"city_code": "101300101",
"city_name": "南宁"
},
{
"_id": 96,
"id": 97,
"pid": 6,
"city_code": "101300501",
"city_name": "桂林"
},
{
"_id": 97,
"id": 98,
"pid": 6,
"city_code": "101301001",
"city_name": "百色"
},
{
"_id": 98,
"id": 99,
"pid": 6,
"city_code": "101301301",
"city_name": "北海"
},
{
"_id": 99,
"id": 100,
"pid": 6,
"city_code": "101300201",
"city_name": "崇左"
},
{
"_id": 100,
"id": 101,
"pid": 6,
"city_code": "101301401",
"city_name": "防城港"
},
{
"_id": 101,
"id": 102,
"pid": 6,
"city_code": "101300801",
"city_name": "贵港"
},
{
"_id": 102,
"id": 103,
"pid": 6,
"city_code": "101301201",
"city_name": "河池"
},
{
"_id": 103,
"id": 104,
"pid": 6,
"city_code": "101300701",
"city_name": "贺州"
},
{
"_id": 104,
"id": 105,
"pid": 6,
"city_code": "101300401",
"city_name": "来宾"
},
{
"_id": 105,
"id": 106,
"pid": 6,
"city_code": "101300301",
"city_name": "柳州"
},
{
"_id": 106,
"id": 107,
"pid": 6,
"city_code": "101301101",
"city_name": "钦州"
},
{
"_id": 107,
"id": 108,
"pid": 6,
"city_code": "101300601",
"city_name": "梧州"
},
{
"_id": 108,
"id": 109,
"pid": 6,
"city_code": "101300901",
"city_name": "玉林"
},
{
"_id": 109,
"id": 110,
"pid": 7,
"city_code": "101260101",
"city_name": "贵阳"
},
{
"_id": 110,
"id": 111,
"pid": 7,
"city_code": "101260301",
"city_name": "安顺"
},
{
"_id": 111,
"id": 112,
"pid": 7,
"city_code": "101260701",
"city_name": "毕节"
},
{
"_id": 112,
"id": 113,
"pid": 7,
"city_code": "101260801",
"city_name": "六盘水"
},
{
"_id": 113,
"id": 114,
"pid": 7,
"city_code": "101260506",
"city_name": "黔东南"
},
{
"_id": 114,
"id": 115,
"pid": 7,
"city_code": "101260413",
"city_name": "黔南"
},
{
"_id": 115,
"id": 116,
"pid": 7,
"city_code": "101260906",
"city_name": "黔西南"
},
{
"_id": 116,
"id": 117,
"pid": 7,
"city_code": "101260601",
"city_name": "铜仁"
},
{
"_id": 117,
"id": 118,
"pid": 7,
"city_code": "101260201",
"city_name": "遵义"
},
{
"_id": 118,
"id": 119,
"pid": 8,
"city_code": "101310101",
"city_name": "海口"
},
{
"_id": 119,
"id": 120,
"pid": 8,
"city_code": "101310201",
"city_name": "三亚"
},
{
"_id": 120,
"id": 121,
"pid": 8,
"city_code": "101310207",
"city_name": "白沙"
},
{
"_id": 121,
"id": 122,
"pid": 8,
"city_code": "101310214",
"city_name": "保亭"
},
{
"_id": 122,
"id": 123,
"pid": 8,
"city_code": "101310206",
"city_name": "昌江"
},
{
"_id": 123,
"id": 124,
"pid": 8,
"city_code": "101310204",
"city_name": "澄迈"
},
{
"_id": 124,
"id": 125,
"pid": 8,
"city_code": "101310209",
"city_name": "定安"
},
{
"_id": 125,
"id": 126,
"pid": 8,
"city_code": "101310202",
"city_name": "东方"
},
{
"_id": 126,
"id": 127,
"pid": 8,
"city_code": "101310221",
"city_name": "乐东"
},
{
"_id": 127,
"id": 128,
"pid": 8,
"city_code": "101310203",
"city_name": "临高"
},
{
"_id": 128,
"id": 129,
"pid": 8,
"city_code": "101310216",
"city_name": "陵水"
},
{
"_id": 129,
"id": 130,
"pid": 8,
"city_code": "101310211",
"city_name": "琼海"
},
{
"_id": 130,
"id": 131,
"pid": 8,
"city_code": "101310208",
"city_name": "琼中"
},
{
"_id": 131,
"id": 132,
"pid": 8,
"city_code": "101310210",
"city_name": "屯昌"
},
{
"_id": 132,
"id": 133,
"pid": 8,
"city_code": "101310215",
"city_name": "万宁"
},
{
"_id": 133,
"id": 134,
"pid": 8,
"city_code": "101310212",
"city_name": "文昌"
},
{
"_id": 134,
"id": 135,
"pid": 8,
"city_code": "101310222",
"city_name": "五指山"
},
{
"_id": 135,
"id": 136,
"pid": 8,
"city_code": "101310205",
"city_name": "儋州"
},
{
"_id": 136,
"id": 137,
"pid": 9,
"city_code": "101090101",
"city_name": "石家庄"
},
{
"_id": 137,
"id": 138,
"pid": 9,
"city_code": "101090201",
"city_name": "保定"
},
{
"_id": 138,
"id": 139,
"pid": 9,
"city_code": "101090701",
"city_name": "沧州"
},
{
"_id": 139,
"id": 140,
"pid": 9,
"city_code": "101090402",
"city_name": "承德"
},
{
"_id": 140,
"id": 141,
"pid": 9,
"city_code": "101091001",
"city_name": "邯郸"
},
{
"_id": 141,
"id": 142,
"pid": 9,
"city_code": "101090801",
"city_name": "衡水"
},
{
"_id": 142,
"id": 143,
"pid": 9,
"city_code": "101090601",
"city_name": "廊坊"
},
{
"_id": 143,
"id": 144,
"pid": 9,
"city_code": "101091101",
"city_name": "秦皇岛"
},
{
"_id": 144,
"id": 145,
"pid": 9,
"city_code": "101090501",
"city_name": "唐山"
},
{
"_id": 145,
"id": 146,
"pid": 9,
"city_code": "101090901",
"city_name": "邢台"
},
{
"_id": 146,
"id": 147,
"pid": 9,
"city_code": "101090301",
"city_name": "张家口"
},
{
"_id": 147,
"id": 148,
"pid": 10,
"city_code": "101180101",
"city_name": "郑州"
},
{
"_id": 148,
"id": 149,
"pid": 10,
"city_code": "101180901",
"city_name": "洛阳"
},
{
"_id": 149,
"id": 150,
"pid": 10,
"city_code": "101180801",
"city_name": "开封"
},
{
"_id": 150,
"id": 151,
"pid": 10,
"city_code": "101180201",
"city_name": "安阳"
},
{
"_id": 151,
"id": 152,
"pid": 10,
"city_code": "101181201",
"city_name": "鹤壁"
},
{
"_id": 152,
"id": 153,
"pid": 10,
"city_code": "101181801",
"city_name": "济源"
},
{
"_id": 153,
"id": 154,
"pid": 10,
"city_code": "101181101",
"city_name": "焦作"
},
{
"_id": 154,
"id": 155,
"pid": 10,
"city_code": "101180701",
"city_name": "南阳"
},
{
"_id": 155,
"id": 156,
"pid": 10,
"city_code": "101180501",
"city_name": "平顶山"
},
{
"_id": 156,
"id": 157,
"pid": 10,
"city_code": "101181701",
"city_name": "三门峡"
},
{
"_id": 157,
"id": 158,
"pid": 10,
"city_code": "101181001",
"city_name": "商丘"
},
{
"_id": 158,
"id": 159,
"pid": 10,
"city_code": "101180301",
"city_name": "新乡"
},
{
"_id": 159,
"id": 160,
"pid": 10,
"city_code": "101180601",
"city_name": "信阳"
},
{
"_id": 160,
"id": 161,
"pid": 10,
"city_code": "101180401",
"city_name": "许昌"
},
{
"_id": 161,
"id": 162,
"pid": 10,
"city_code": "101181401",
"city_name": "周口"
},
{
"_id": 162,
"id": 163,
"pid": 10,
"city_code": "101181601",
"city_name": "驻马店"
},
{
"_id": 163,
"id": 164,
"pid": 10,
"city_code": "101181501",
"city_name": "漯河"
},
{
"_id": 164,
"id": 165,
"pid": 10,
"city_code": "101181301",
"city_name": "濮阳"
},
{
"_id": 165,
"id": 166,
"pid": 11,
"city_code": "101050101",
"city_name": "哈尔滨"
},
{
"_id": 166,
"id": 167,
"pid": 11,
"city_code": "101050901",
"city_name": "大庆"
},
{
"_id": 167,
"id": 168,
"pid": 11,
"city_code": "101050701",
"city_name": "大兴安岭"
},
{
"_id": 168,
"id": 169,
"pid": 11,
"city_code": "101051201",
"city_name": "鹤岗"
},
{
"_id": 169,
"id": 170,
"pid": 11,
"city_code": "101050601",
"city_name": "黑河"
},
{
"_id": 170,
"id": 171,
"pid": 11,
"city_code": "101051101",
"city_name": "鸡西"
},
{
"_id": 171,
"id": 172,
"pid": 11,
"city_code": "101050401",
"city_name": "佳木斯"
},
{
"_id": 172,
"id": 173,
"pid": 11,
"city_code": "101050301",
"city_name": "牡丹江"
},
{
"_id": 173,
"id": 174,
"pid": 11,
"city_code": "101051002",
"city_name": "七台河"
},
{
"_id": 174,
"id": 175,
"pid": 11,
"city_code": "101050201",
"city_name": "齐齐哈尔"
},
{
"_id": 175,
"id": 176,
"pid": 11,
"city_code": "101051301",
"city_name": "双鸭山"
},
{
"_id": 176,
"id": 177,
"pid": 11,
"city_code": "101050501",
"city_name": "绥化"
},
{
"_id": 177,
"id": 178,
"pid": 11,
"city_code": "101050801",
"city_name": "伊春"
},
{
"_id": 178,
"id": 179,
"pid": 12,
"city_code": "101200101",
"city_name": "武汉"
},
{
"_id": 179,
"id": 180,
"pid": 12,
"city_code": "101201601",
"city_name": "仙桃"
},
{
"_id": 180,
"id": 181,
"pid": 12,
"city_code": "101200301",
"city_name": "鄂州"
},
{
"_id": 181,
"id": 182,
"pid": 12,
"city_code": "101200501",
"city_name": "黄冈"
},
{
"_id": 182,
"id": 183,
"pid": 12,
"city_code": "101200601",
"city_name": "黄石"
},
{
"_id": 183,
"id": 184,
"pid": 12,
"city_code": "101201401",
"city_name": "荆门"
},
{
"_id": 184,
"id": 185,
"pid": 12,
"city_code": "101200801",
"city_name": "荆州"
},
{
"_id": 185,
"id": 186,
"pid": 12,
"city_code": "101201701",
"city_name": "潜江"
},
{
"_id": 186,
"id": 187,
"pid": 12,
"city_code": "101201201",
"city_name": "神农架林"
},
{
"_id": 187,
"id": 188,
"pid": 12,
"city_code": "101201101",
"city_name": "十堰"
},
{
"_id": 188,
"id": 189,
"pid": 12,
"city_code": "101201301",
"city_name": "随州"
},
{
"_id": 189,
"id": 190,
"pid": 12,
"city_code": "101201501",
"city_name": "天门"
},
{
"_id": 190,
"id": 191,
"pid": 12,
"city_code": "101200701",
"city_name": "咸宁"
},
{
"_id": 191,
"id": 192,
"pid": 12,
"city_code": "101200202",
"city_name": "襄阳"
},
{
"_id": 192,
"id": 193,
"pid": 12,
"city_code": "101200401",
"city_name": "孝感"
},
{
"_id": 193,
"id": 194,
"pid": 12,
"city_code": "101200901",
"city_name": "宜昌"
},
{
"_id": 194,
"id": 195,
"pid": 12,
"city_code": "101201001",
"city_name": "恩施"
},
{
"_id": 195,
"id": 196,
"pid": 13,
"city_code": "101250101",
"city_name": "长沙"
},
{
"_id": 196,
"id": 197,
"pid": 13,
"city_code": "101251101",
"city_name": "张家界"
},
{
"_id": 197,
"id": 198,
"pid": 13,
"city_code": "101250601",
"city_name": "常德"
},
{
"_id": 198,
"id": 199,
"pid": 13,
"city_code": "101250501",
"city_name": "郴州"
},
{
"_id": 199,
"id": 200,
"pid": 13,
"city_code": "101250401",
"city_name": "衡阳"
},
{
"_id": 200,
"id": 201,
"pid": 13,
"city_code": "101251201",
"city_name": "怀化"
},
{
"_id": 201,
"id": 202,
"pid": 13,
"city_code": "101250801",
"city_name": "娄底"
},
{
"_id": 202,
"id": 203,
"pid": 13,
"city_code": "101250901",
"city_name": "邵阳"
},
{
"_id": 203,
"id": 204,
"pid": 13,
"city_code": "101250201",
"city_name": "湘潭"
},
{
"_id": 204,
"id": 205,
"pid": 13,
"city_code": "101251509",
"city_name": "湘西"
},
{
"_id": 205,
"id": 206,
"pid": 13,
"city_code": "101250700",
"city_name": "益阳"
},
{
"_id": 206,
"id": 207,
"pid": 13,
"city_code": "101251401",
"city_name": "永州"
},
{
"_id": 207,
"id": 208,
"pid": 13,
"city_code": "101251001",
"city_name": "岳阳"
},
{
"_id": 208,
"id": 209,
"pid": 13,
"city_code": "101250301",
"city_name": "株洲"
},
{
"_id": 209,
"id": 210,
"pid": 14,
"city_code": "101060101",
"city_name": "长春"
},
{
"_id": 210,
"id": 211,
"pid": 14,
"city_code": "101060201",
"city_name": "吉林"
},
{
"_id": 211,
"id": 212,
"pid": 14,
"city_code": "101060601",
"city_name": "白城"
},
{
"_id": 212,
"id": 213,
"pid": 14,
"city_code": "101060901",
"city_name": "白山"
},
{
"_id": 213,
"id": 214,
"pid": 14,
"city_code": "101060701",
"city_name": "辽源"
},
{
"_id": 214,
"id": 215,
"pid": 14,
"city_code": "101060401",
"city_name": "四平"
},
{
"_id": 215,
"id": 216,
"pid": 14,
"city_code": "101060801",
"city_name": "松原"
},
{
"_id": 216,
"id": 217,
"pid": 14,
"city_code": "101060501",
"city_name": "通化"
},
{
"_id": 217,
"id": 218,
"pid": 14,
"city_code": "101060312",
"city_name": "延边"
},
{
"_id": 218,
"id": 219,
"pid": 15,
"city_code": "101190101",
"city_name": "南京"
},
{
"_id": 219,
"id": 220,
"pid": 15,
"city_code": "101190401",
"city_name": "苏州"
},
{
"_id": 220,
"id": 221,
"pid": 15,
"city_code": "101190201",
"city_name": "无锡"
},
{
"_id": 221,
"id": 222,
"pid": 15,
"city_code": "101191101",
"city_name": "常州"
},
{
"_id": 222,
"id": 223,
"pid": 15,
"city_code": "101190901",
"city_name": "淮安"
},
{
"_id": 223,
"id": 224,
"pid": 15,
"city_code": "101191001",
"city_name": "连云港"
},
{
"_id": 224,
"id": 225,
"pid": 15,
"city_code": "101190501",
"city_name": "南通"
},
{
"_id": 225,
"id": 226,
"pid": 15,
"city_code": "101191301",
"city_name": "宿迁"
},
{
"_id": 226,
"id": 227,
"pid": 15,
"city_code": "101191201",
"city_name": "泰州"
},
{
"_id": 227,
"id": 228,
"pid": 15,
"city_code": "101190801",
"city_name": "徐州"
},
{
"_id": 228,
"id": 229,
"pid": 15,
"city_code": "101190701",
"city_name": "盐城"
},
{
"_id": 229,
"id": 230,
"pid": 15,
"city_code": "101190601",
"city_name": "扬州"
},
{
"_id": 230,
"id": 231,
"pid": 15,
"city_code": "101190301",
"city_name": "镇江"
},
{
"_id": 231,
"id": 232,
"pid": 16,
"city_code": "101240101",
"city_name": "南昌"
},
{
"_id": 232,
"id": 233,
"pid": 16,
"city_code": "101240401",
"city_name": "抚州"
},
{
"_id": 233,
"id": 234,
"pid": 16,
"city_code": "101240701",
"city_name": "赣州"
},
{
"_id": 234,
"id": 235,
"pid": 16,
"city_code": "101240601",
"city_name": "吉安"
},
{
"_id": 235,
"id": 236,
"pid": 16,
"city_code": "101240801",
"city_name": "景德镇"
},
{
"_id": 236,
"id": 237,
"pid": 16,
"city_code": "101240201",
"city_name": "九江"
},
{
"_id": 237,
"id": 238,
"pid": 16,
"city_code": "101240901",
"city_name": "萍乡"
},
{
"_id": 238,
"id": 239,
"pid": 16,
"city_code": "101240301",
"city_name": "上饶"
},
{
"_id": 239,
"id": 240,
"pid": 16,
"city_code": "101241001",
"city_name": "新余"
},
{
"_id": 240,
"id": 241,
"pid": 16,
"city_code": "101240501",
"city_name": "宜春"
},
{
"_id": 241,
"id": 242,
"pid": 16,
"city_code": "101241101",
"city_name": "鹰潭"
},
{
"_id": 242,
"id": 243,
"pid": 17,
"city_code": "101070101",
"city_name": "沈阳"
},
{
"_id": 243,
"id": 244,
"pid": 17,
"city_code": "101070201",
"city_name": "大连"
},
{
"_id": 244,
"id": 245,
"pid": 17,
"city_code": "101070301",
"city_name": "鞍山"
},
{
"_id": 245,
"id": 246,
"pid": 17,
"city_code": "101070501",
"city_name": "本溪"
},
{
"_id": 246,
"id": 247,
"pid": 17,
"city_code": "101071201",
"city_name": "朝阳市"
},
{
"_id": 247,
"id": 248,
"pid": 17,
"city_code": "101070601",
"city_name": "丹东"
},
{
"_id": 248,
"id": 249,
"pid": 17,
"city_code": "101070401",
"city_name": "抚顺"
},
{
"_id": 249,
"id": 250,
"pid": 17,
"city_code": "101070901",
"city_name": "阜新"
},
{
"_id": 250,
"id": 251,
"pid": 17,
"city_code": "101071401",
"city_name": "葫芦岛"
},
{
"_id": 251,
"id": 252,
"pid": 17,
"city_code": "101070701",
"city_name": "锦州"
},
{
"_id": 252,
"id": 253,
"pid": 17,
"city_code": "101071001",
"city_name": "辽阳"
},
{
"_id": 253,
"id": 254,
"pid": 17,
"city_code": "101071301",
"city_name": "盘锦"
},
{
"_id": 254,
"id": 255,
"pid": 17,
"city_code": "101071101",
"city_name": "铁岭"
},
{
"_id": 255,
"id": 256,
"pid": 17,
"city_code": "101070801",
"city_name": "营口"
},
{
"_id": 256,
"id": 257,
"pid": 18,
"city_code": "101080101",
"city_name": "呼和浩特"
},
{
"_id": 257,
"id": 258,
"pid": 18,
"city_code": "101081213",
"city_name": "阿拉善盟"
},
{
"_id": 258,
"id": 259,
"pid": 18,
"city_code": "101080801",
"city_name": "巴彦淖尔"
},
{
"_id": 259,
"id": 260,
"pid": 18,
"city_code": "101080201",
"city_name": "包头"
},
{
"_id": 260,
"id": 261,
"pid": 18,
"city_code": "101080601",
"city_name": "赤峰"
},
{
"_id": 261,
"id": 262,
"pid": 18,
"city_code": "101080701",
"city_name": "鄂尔多斯"
},
{
"_id": 262,
"id": 263,
"pid": 18,
"city_code": "101081001",
"city_name": "呼伦贝尔"
},
{
"_id": 263,
"id": 264,
"pid": 18,
"city_code": "101080501",
"city_name": "通辽"
},
{
"_id": 264,
"id": 265,
"pid": 18,
"city_code": "101080301",
"city_name": "乌海"
},
{
"_id": 265,
"id": 266,
"pid": 18,
"city_code": "101080405",
"city_name": "乌兰察布"
},
{
"_id": 266,
"id": 267,
"pid": 18,
"city_code": "101080902",
"city_name": "锡林郭勒"
},
{
"_id": 267,
"id": 268,
"pid": 18,
"city_code": "101081108",
"city_name": "兴安盟"
},
{
"_id": 268,
"id": 269,
"pid": 19,
"city_code": "101170101",
"city_name": "银川"
},
{
"_id": 269,
"id": 270,
"pid": 19,
"city_code": "101170401",
"city_name": "固原"
},
{
"_id": 270,
"id": 271,
"pid": 19,
"city_code": "101170201",
"city_name": "石嘴山"
},
{
"_id": 271,
"id": 272,
"pid": 19,
"city_code": "101170301",
"city_name": "吴忠"
},
{
"_id": 272,
"id": 273,
"pid": 19,
"city_code": "101170501",
"city_name": "中卫"
},
{
"_id": 273,
"id": 274,
"pid": 20,
"city_code": "101150101",
"city_name": "西宁"
},
{
"_id": 274,
"id": 275,
"pid": 20,
"city_code": "101150501",
"city_name": "果洛"
},
{
"_id": 275,
"id": 276,
"pid": 20,
"city_code": "101150801",
"city_name": "海北"
},
{
"_id": 276,
"id": 277,
"pid": 20,
"city_code": "101150201",
"city_name": "海东"
},
{
"_id": 277,
"id": 278,
"pid": 20,
"city_code": "101150401",
"city_name": "海南州"
},
{
"_id": 278,
"id": 279,
"pid": 20,
"city_code": "101150701",
"city_name": "海西"
},
{
"_id": 279,
"id": 280,
"pid": 20,
"city_code": "101150301",
"city_name": "黄南"
},
{
"_id": 280,
"id": 281,
"pid": 20,
"city_code": "101150601",
"city_name": "玉树"
},
{
"_id": 281,
"id": 282,
"pid": 21,
"city_code": "101120101",
"city_name": "济南"
},
{
"_id": 282,
"id": 283,
"pid": 21,
"city_code": "101120201",
"city_name": "青岛"
},
{
"_id": 283,
"id": 284,
"pid": 21,
"city_code": "101121101",
"city_name": "滨州"
},
{
"_id": 284,
"id": 285,
"pid": 21,
"city_code": "101120401",
"city_name": "德州"
},
{
"_id": 285,
"id": 286,
"pid": 21,
"city_code": "101121201",
"city_name": "东营"
},
{
"_id": 286,
"id": 287,
"pid": 21,
"city_code": "101121001",
"city_name": "菏泽"
},
{
"_id": 287,
"id": 288,
"pid": 21,
"city_code": "101120701",
"city_name": "济宁"
},
{
"_id": 288,
"id": 289,
"pid": 21,
"city_code": "101121601",
"city_name": "莱芜"
},
{
"_id": 289,
"id": 290,
"pid": 21,
"city_code": "101121701",
"city_name": "聊城"
},
{
"_id": 290,
"id": 291,
"pid": 21,
"city_code": "101120901",
"city_name": "临沂"
},
{
"_id": 291,
"id": 292,
"pid": 21,
"city_code": "101121501",
"city_name": "日照"
},
{
"_id": 292,
"id": 293,
"pid": 21,
"city_code": "101120801",
"city_name": "泰安"
},
{
"_id": 293,
"id": 294,
"pid": 21,
"city_code": "101121301",
"city_name": "威海"
},
{
"_id": 294,
"id": 295,
"pid": 21,
"city_code": "101120601",
"city_name": "潍坊"
},
{
"_id": 295,
"id": 296,
"pid": 21,
"city_code": "101120501",
"city_name": "烟台"
},
{
"_id": 296,
"id": 297,
"pid": 21,
"city_code": "101121401",
"city_name": "枣庄"
},
{
"_id": 297,
"id": 298,
"pid": 21,
"city_code": "101120301",
"city_name": "淄博"
},
{
"_id": 298,
"id": 299,
"pid": 22,
"city_code": "101100101",
"city_name": "太原"
},
{
"_id": 299,
"id": 300,
"pid": 22,
"city_code": "101100501",
"city_name": "长治"
},
{
"_id": 300,
"id": 301,
"pid": 22,
"city_code": "101100201",
"city_name": "大同"
},
{
"_id": 301,
"id": 302,
"pid": 22,
"city_code": "101100601",
"city_name": "晋城"
},
{
"_id": 302,
"id": 303,
"pid": 22,
"city_code": "101100401",
"city_name": "晋中"
},
{
"_id": 303,
"id": 304,
"pid": 22,
"city_code": "101100701",
"city_name": "临汾"
},
{
"_id": 304,
"id": 305,
"pid": 22,
"city_code": "101101100",
"city_name": "吕梁"
},
{
"_id": 305,
"id": 306,
"pid": 22,
"city_code": "101100901",
"city_name": "朔州"
},
{
"_id": 306,
"id": 307,
"pid": 22,
"city_code": "101101001",
"city_name": "忻州"
},
{
"_id": 307,
"id": 308,
"pid": 22,
"city_code": "101100301",
"city_name": "阳泉"
},
{
"_id": 308,
"id": 309,
"pid": 22,
"city_code": "101100801",
"city_name": "运城"
},
{
"_id": 309,
"id": 310,
"pid": 23,
"city_code": "101110101",
"city_name": "西安"
},
{
"_id": 310,
"id": 311,
"pid": 23,
"city_code": "101110701",
"city_name": "安康"
},
{
"_id": 311,
"id": 312,
"pid": 23,
"city_code": "101110901",
"city_name": "宝鸡"
},
{
"_id": 312,
"id": 313,
"pid": 23,
"city_code": "101110801",
"city_name": "汉中"
},
{
"_id": 313,
"id": 314,
"pid": 23,
"city_code": "101110601",
"city_name": "商洛"
},
{
"_id": 314,
"id": 315,
"pid": 23,
"city_code": "101111001",
"city_name": "铜川"
},
{
"_id": 315,
"id": 316,
"pid": 23,
"city_code": "101110501",
"city_name": "渭南"
},
{
"_id": 316,
"id": 317,
"pid": 23,
"city_code": "101110200",
"city_name": "咸阳"
},
{
"_id": 317,
"id": 318,
"pid": 23,
"city_code": "101110300",
"city_name": "延安"
},
{
"_id": 318,
"id": 319,
"pid": 23,
"city_code": "101110401",
"city_name": "榆林"
},
{
"_id": 319,
"id": 321,
"pid": 25,
"city_code": "101270101",
"city_name": "成都"
},
{
"_id": 320,
"id": 322,
"pid": 25,
"city_code": "101270401",
"city_name": "绵阳"
},
{
"_id": 321,
"id": 323,
"pid": 25,
"city_code": "101271901",
"city_name": "阿坝"
},
{
"_id": 322,
"id": 324,
"pid": 25,
"city_code": "101270901",
"city_name": "巴中"
},
{
"_id": 323,
"id": 325,
"pid": 25,
"city_code": "101270601",
"city_name": "达州"
},
{
"_id": 324,
"id": 326,
"pid": 25,
"city_code": "101272001",
"city_name": "德阳"
},
{
"_id": 325,
"id": 327,
"pid": 25,
"city_code": "101271801",
"city_name": "甘孜"
},
{
"_id": 326,
"id": 328,
"pid": 25,
"city_code": "101270801",
"city_name": "广安"
},
{
"_id": 327,
"id": 329,
"pid": 25,
"city_code": "101272101",
"city_name": "广元"
},
{
"_id": 328,
"id": 330,
"pid": 25,
"city_code": "101271401",
"city_name": "乐山"
},
{
"_id": 329,
"id": 331,
"pid": 25,
"city_code": "101271601",
"city_name": "凉山"
},
{
"_id": 330,
"id": 332,
"pid": 25,
"city_code": "101271501",
"city_name": "眉山"
},
{
"_id": 331,
"id": 333,
"pid": 25,
"city_code": "101270501",
"city_name": "南充"
},
{
"_id": 332,
"id": 334,
"pid": 25,
"city_code": "101271201",
"city_name": "内江"
},
{
"_id": 333,
"id": 335,
"pid": 25,
"city_code": "101270201",
"city_name": "攀枝花"
},
{
"_id": 334,
"id": 336,
"pid": 25,
"city_code": "101270701",
"city_name": "遂宁"
},
{
"_id": 335,
"id": 337,
"pid": 25,
"city_code": "101271701",
"city_name": "雅安"
},
{
"_id": 336,
"id": 338,
"pid": 25,
"city_code": "101271101",
"city_name": "宜宾"
},
{
"_id": 337,
"id": 339,
"pid": 25,
"city_code": "101271301",
"city_name": "资阳"
},
{
"_id": 338,
"id": 340,
"pid": 25,
"city_code": "101270301",
"city_name": "自贡"
},
{
"_id": 339,
"id": 341,
"pid": 25,
"city_code": "101271001",
"city_name": "泸州"
},
{
"_id": 340,
"id": 343,
"pid": 27,
"city_code": "101140101",
"city_name": "拉萨"
},
{
"_id": 341,
"id": 344,
"pid": 27,
"city_code": "101140701",
"city_name": "阿里"
},
{
"_id": 342,
"id": 345,
"pid": 27,
"city_code": "101140501",
"city_name": "昌都"
},
{
"_id": 343,
"id": 346,
"pid": 27,
"city_code": "101140401",
"city_name": "林芝"
},
{
"_id": 344,
"id": 347,
"pid": 27,
"city_code": "101140601",
"city_name": "那曲"
},
{
"_id": 345,
"id": 348,
"pid": 27,
"city_code": "101140201",
"city_name": "日喀则"
},
{
"_id": 346,
"id": 349,
"pid": 27,
"city_code": "101140301",
"city_name": "山南"
},
{
"_id": 347,
"id": 350,
"pid": 28,
"city_code": "101130101",
"city_name": "乌鲁木齐"
},
{
"_id": 348,
"id": 351,
"pid": 28,
"city_code": "101130801",
"city_name": "阿克苏"
},
{
"_id": 349,
"id": 352,
"pid": 28,
"city_code": "101130701",
"city_name": "阿拉尔"
},
{
"_id": 350,
"id": 353,
"pid": 28,
"city_code": "101130609",
"city_name": "巴音郭楞"
},
{
"_id": 351,
"id": 354,
"pid": 28,
"city_code": "101131604",
"city_name": "博尔塔拉"
},
{
"_id": 352,
"id": 355,
"pid": 28,
"city_code": "101130401",
"city_name": "昌吉"
},
{
"_id": 353,
"id": 356,
"pid": 28,
"city_code": "101131201",
"city_name": "哈密"
},
{
"_id": 354,
"id": 357,
"pid": 28,
"city_code": "101131301",
"city_name": "和田"
},
{
"_id": 355,
"id": 358,
"pid": 28,
"city_code": "101130901",
"city_name": "喀什"
},
{
"_id": 356,
"id": 359,
"pid": 28,
"city_code": "101130201",
"city_name": "克拉玛依"
},
{
"_id": 357,
"id": 360,
"pid": 28,
"city_code": "",
"city_name": "克孜勒苏"
},
{
"_id": 358,
"id": 361,
"pid": 28,
"city_code": "101130301",
"city_name": "石河子"
},
{
"_id": 359,
"id": 362,
"pid": 28,
"city_code": "",
"city_name": "图木舒克"
},
{
"_id": 360,
"id": 363,
"pid": 28,
"city_code": "101130501",
"city_name": "吐鲁番"
},
{
"_id": 361,
"id": 364,
"pid": 28,
"city_code": "",
"city_name": "五家渠"
},
{
"_id": 362,
"id": 365,
"pid": 28,
"city_code": "101131012",
"city_name": "伊犁"
},
{
"_id": 363,
"id": 366,
"pid": 29,
"city_code": "101290101",
"city_name": "昆明"
},
{
"_id": 364,
"id": 367,
"pid": 29,
"city_code": "101291201",
"city_name": "怒江"
},
{
"_id": 365,
"id": 368,
"pid": 29,
"city_code": "101290901",
"city_name": "普洱"
},
{
"_id": 366,
"id": 369,
"pid": 29,
"city_code": "101291401",
"city_name": "丽江"
},
{
"_id": 367,
"id": 370,
"pid": 29,
"city_code": "101290501",
"city_name": "保山"
},
{
"_id": 368,
"id": 371,
"pid": 29,
"city_code": "101290801",
"city_name": "楚雄"
},
{
"_id": 369,
"id": 372,
"pid": 29,
"city_code": "101290201",
"city_name": "大理"
},
{
"_id": 370,
"id": 373,
"pid": 29,
"city_code": "101291501",
"city_name": "德宏"
},
{
"_id": 371,
"id": 374,
"pid": 29,
"city_code": "101291305",
"city_name": "迪庆"
},
{
"_id": 372,
"id": 375,
"pid": 29,
"city_code": "101290301",
"city_name": "红河"
},
{
"_id": 373,
"id": 376,
"pid": 29,
"city_code": "101291101",
"city_name": "临沧"
},
{
"_id": 374,
"id": 377,
"pid": 29,
"city_code": "101290401",
"city_name": "曲靖"
},
{
"_id": 375,
"id": 378,
"pid": 29,
"city_code": "101290601",
"city_name": "文山"
},
{
"_id": 376,
"id": 379,
"pid": 29,
"city_code": "101291602",
"city_name": "西双版纳"
},
{
"_id": 377,
"id": 380,
"pid": 29,
"city_code": "101290701",
"city_name": "玉溪"
},
{
"_id": 378,
"id": 381,
"pid": 29,
"city_code": "101291001",
"city_name": "昭通"
},
{
"_id": 379,
"id": 382,
"pid": 30,
"city_code": "101210101",
"city_name": "杭州"
},
{
"_id": 380,
"id": 383,
"pid": 30,
"city_code": "101210201",
"city_name": "湖州"
},
{
"_id": 381,
"id": 384,
"pid": 30,
"city_code": "101210301",
"city_name": "嘉兴"
},
{
"_id": 382,
"id": 385,
"pid": 30,
"city_code": "101210901",
"city_name": "金华"
},
{
"_id": 383,
"id": 386,
"pid": 30,
"city_code": "101210801",
"city_name": "丽水"
},
{
"_id": 384,
"id": 387,
"pid": 30,
"city_code": "101210401",
"city_name": "宁波"
},
{
"_id": 385,
"id": 388,
"pid": 30,
"city_code": "101210501",
"city_name": "绍兴"
},
{
"_id": 386,
"id": 389,
"pid": 30,
"city_code": "101210601",
"city_name": "台州"
},
{
"_id": 387,
"id": 390,
"pid": 30,
"city_code": "101210701",
"city_name": "温州"
},
{
"_id": 388,
"id": 391,
"pid": 30,
"city_code": "101211101",
"city_name": "舟山"
},
{
"_id": 389,
"id": 392,
"pid": 30,
"city_code": "101211001",
"city_name": "衢州"
},
{
"_id": 390,
"id": 400,
"pid": 35,
"city_code": "101220609",
"city_name": "桐城"
},
{
"_id": 391,
"id": 401,
"pid": 35,
"city_code": "101220605",
"city_name": "怀宁"
},
{
"_id": 392,
"id": 402,
"pid": 47,
"city_code": "101220602",
"city_name": "枞阳"
},
{
"_id": 393,
"id": 403,
"pid": 35,
"city_code": "101220604",
"city_name": "潜山"
},
{
"_id": 394,
"id": 404,
"pid": 35,
"city_code": "101220603",
"city_name": "太湖"
},
{
"_id": 395,
"id": 405,
"pid": 35,
"city_code": "101220606",
"city_name": "宿松"
},
{
"_id": 396,
"id": 406,
"pid": 35,
"city_code": "101220607",
"city_name": "望江"
},
{
"_id": 397,
"id": 407,
"pid": 35,
"city_code": "101220608",
"city_name": "岳西"
},
{
"_id": 398,
"id": 412,
"pid": 36,
"city_code": "101220202",
"city_name": "怀远"
},
{
"_id": 399,
"id": 413,
"pid": 36,
"city_code": "101220204",
"city_name": "五河"
},
{
"_id": 400,
"id": 414,
"pid": 36,
"city_code": "101220203",
"city_name": "固镇"
},
{
"_id": 401,
"id": 416,
"pid": 3400,
"city_code": "101220106",
"city_name": "庐江"
},
{
"_id": 402,
"id": 417,
"pid": 48,
"city_code": "101220305",
"city_name": "无为"
},
{
"_id": 403,
"id": 418,
"pid": 45,
"city_code": "101220503",
"city_name": "含山"
},
{
"_id": 404,
"id": 419,
"pid": 45,
"city_code": "101220504",
"city_name": "和"
},
{
"_id": 405,
"id": 421,
"pid": 38,
"city_code": "101221702",
"city_name": "东至"
},
{
"_id": 406,
"id": 422,
"pid": 38,
"city_code": "101221705",
"city_name": "石台"
},
{
"_id": 407,
"id": 423,
"pid": 38,
"city_code": "101221703",
"city_name": "青阳"
},
{
"_id": 408,
"id": 426,
"pid": 39,
"city_code": "101221107",
"city_name": "天长"
},
{
"_id": 409,
"id": 427,
"pid": 39,
"city_code": "101221103",
"city_name": "明光"
},
{
"_id": 410,
"id": 428,
"pid": 39,
"city_code": "101221106",
"city_name": "来安"
},
{
"_id": 411,
"id": 429,
"pid": 39,
"city_code": "101221105",
"city_name": "全椒"
},
{
"_id": 412,
"id": 430,
"pid": 39,
"city_code": "101221104",
"city_name": "定远"
},
{
"_id": 413,
"id": 431,
"pid": 39,
"city_code": "101221102",
"city_name": "凤阳"
},
{
"_id": 414,
"id": 439,
"pid": 40,
"city_code": "101220805",
"city_name": "界首"
},
{
"_id": 415,
"id": 440,
"pid": 40,
"city_code": "101220804",
"city_name": "临泉"
},
{
"_id": 416,
"id": 441,
"pid": 40,
"city_code": "101220806",
"city_name": "太和"
},
{
"_id": 417,
"id": 442,
"pid": 40,
"city_code": "101220802",
"city_name": "阜南"
},
{
"_id": 418,
"id": 443,
"pid": 40,
"city_code": "101220803",
"city_name": "颍上"
},
{
"_id": 419,
"id": 447,
"pid": 41,
"city_code": "101221202",
"city_name": "濉溪"
},
{
"_id": 420,
"id": 452,
"pid": 42,
"city_code": "101220403",
"city_name": "潘集"
},
{
"_id": 421,
"id": 453,
"pid": 42,
"city_code": "101220402",
"city_name": "凤台"
},
{
"_id": 422,
"id": 454,
"pid": 43,
"city_code": "101221003",
"city_name": "屯溪"
},
{
"_id": 423,
"id": 455,
"pid": 43,
"city_code": "101221002",
"city_name": "黄山"
},
{
"_id": 424,
"id": 457,
"pid": 43,
"city_code": "101221006",
"city_name": "歙"
},
{
"_id": 425,
"id": 458,
"pid": 43,
"city_code": "101221007",
"city_name": "休宁"
},
{
"_id": 426,
"id": 459,
"pid": 43,
"city_code": "101221005",
"city_name": "黟"
},
{
"_id": 427,
"id": 460,
"pid": 43,
"city_code": "101221004",
"city_name": "祁门"
},
{
"_id": 428,
"id": 463,
"pid": 44,
"city_code": "101221503",
"city_name": "寿"
},
{
"_id": 429,
"id": 464,
"pid": 44,
"city_code": "101221502",
"city_name": "霍邱"
},
{
"_id": 430,
"id": 465,
"pid": 44,
"city_code": "101221507",
"city_name": "舒城"
},
{
"_id": 431,
"id": 466,
"pid": 44,
"city_code": "101221505",
"city_name": "金寨"
},
{
"_id": 432,
"id": 467,
"pid": 44,
"city_code": "101221506",
"city_name": "霍山"
},
{
"_id": 433,
"id": 471,
"pid": 45,
"city_code": "101220502",
"city_name": "当涂"
},
{
"_id": 434,
"id": 473,
"pid": 46,
"city_code": "101220702",
"city_name": "砀山"
},
{
"_id": 435,
"id": 474,
"pid": 46,
"city_code": "101220705",
"city_name": "萧"
},
{
"_id": 436,
"id": 475,
"pid": 46,
"city_code": "101220703",
"city_name": "灵璧"
},
{
"_id": 437,
"id": 476,
"pid": 46,
"city_code": "101220704",
"city_name": "泗"
},
{
"_id": 438,
"id": 480,
"pid": 47,
"city_code": "101221301",
"city_name": "义安"
},
{
"_id": 439,
"id": 485,
"pid": 48,
"city_code": "101220303",
"city_name": "芜湖"
},
{
"_id": 440,
"id": 486,
"pid": 48,
"city_code": "101220302",
"city_name": "繁昌"
},
{
"_id": 441,
"id": 487,
"pid": 48,
"city_code": "101220304",
"city_name": "南陵"
},
{
"_id": 442,
"id": 489,
"pid": 49,
"city_code": "101221404",
"city_name": "宁国"
},
{
"_id": 443,
"id": 490,
"pid": 49,
"city_code": "101221407",
"city_name": "郎溪"
},
{
"_id": 444,
"id": 491,
"pid": 49,
"city_code": "101221406",
"city_name": "广德"
},
{
"_id": 445,
"id": 492,
"pid": 49,
"city_code": "101221402",
"city_name": "泾"
},
{
"_id": 446,
"id": 493,
"pid": 49,
"city_code": "101221405",
"city_name": "绩溪"
},
{
"_id": 447,
"id": 494,
"pid": 49,
"city_code": "101221403",
"city_name": "旌德"
},
{
"_id": 448,
"id": 495,
"pid": 50,
"city_code": "101220902",
"city_name": "涡阳"
},
{
"_id": 449,
"id": 496,
"pid": 50,
"city_code": "101220904",
"city_name": "蒙城"
},
{
"_id": 450,
"id": 497,
"pid": 50,
"city_code": "101220903",
"city_name": "利辛"
},
{
"_id": 451,
"id": 501,
"pid": 1,
"city_code": "101010200",
"city_name": "海淀"
},
{
"_id": 452,
"id": 502,
"pid": 1,
"city_code": "101010300",
"city_name": "朝阳"
},
{
"_id": 453,
"id": 505,
"pid": 1,
"city_code": "101010900",
"city_name": "丰台"
},
{
"_id": 454,
"id": 506,
"pid": 1,
"city_code": "101011000",
"city_name": "石景山"
},
{
"_id": 455,
"id": 507,
"pid": 1,
"city_code": "101011200",
"city_name": "房山"
},
{
"_id": 456,
"id": 508,
"pid": 1,
"city_code": "101011400",
"city_name": "门头沟"
},
{
"_id": 457,
"id": 509,
"pid": 1,
"city_code": "101010600",
"city_name": "通州"
},
{
"_id": 458,
"id": 510,
"pid": 1,
"city_code": "101010400",
"city_name": "顺义"
},
{
"_id": 459,
"id": 511,
"pid": 1,
"city_code": "101010700",
"city_name": "昌平"
},
{
"_id": 460,
"id": 512,
"pid": 1,
"city_code": "101010500",
"city_name": "怀柔"
},
{
"_id": 461,
"id": 513,
"pid": 1,
"city_code": "101011500",
"city_name": "平谷"
},
{
"_id": 462,
"id": 514,
"pid": 1,
"city_code": "101011100",
"city_name": "大兴"
},
{
"_id": 463,
"id": 515,
"pid": 1,
"city_code": "101011300",
"city_name": "密云"
},
{
"_id": 464,
"id": 516,
"pid": 1,
"city_code": "101010800",
"city_name": "延庆"
},
{
"_id": 465,
"id": 522,
"pid": 52,
"city_code": "101230111",
"city_name": "福清"
},
{
"_id": 466,
"id": 523,
"pid": 52,
"city_code": "101230110",
"city_name": "长乐"
},
{
"_id": 467,
"id": 524,
"pid": 52,
"city_code": "101230103",
"city_name": "闽侯"
},
{
"_id": 468,
"id": 525,
"pid": 52,
"city_code": "101230105",
"city_name": "连江"
},
{
"_id": 469,
"id": 526,
"pid": 52,
"city_code": "101230104",
"city_name": "罗源"
},
{
"_id": 470,
"id": 527,
"pid": 52,
"city_code": "101230102",
"city_name": "闽清"
},
{
"_id": 471,
"id": 528,
"pid": 52,
"city_code": "101230107",
"city_name": "永泰"
},
{
"_id": 472,
"id": 529,
"pid": 52,
"city_code": "101230108",
"city_name": "平潭"
},
{
"_id": 473,
"id": 531,
"pid": 53,
"city_code": "101230707",
"city_name": "漳平"
},
{
"_id": 474,
"id": 532,
"pid": 53,
"city_code": "101230702",
"city_name": "长汀"
},
{
"_id": 475,
"id": 533,
"pid": 53,
"city_code": "101230706",
"city_name": "永定"
},
{
"_id": 476,
"id": 534,
"pid": 53,
"city_code": "101230705",
"city_name": "上杭"
},
{
"_id": 477,
"id": 535,
"pid": 53,
"city_code": "101230704",
"city_name": "武平"
},
{
"_id": 478,
"id": 536,
"pid": 53,
"city_code": "101230703",
"city_name": "连城"
},
{
"_id": 479,
"id": 538,
"pid": 54,
"city_code": "101230904",
"city_name": "邵武"
},
{
"_id": 480,
"id": 539,
"pid": 54,
"city_code": "101230905",
"city_name": "武夷山"
},
{
"_id": 481,
"id": 540,
"pid": 54,
"city_code": "101230910",
"city_name": "建瓯"
},
{
"_id": 482,
"id": 541,
"pid": 54,
"city_code": "101230907",
"city_name": "建阳"
},
{
"_id": 483,
"id": 542,
"pid": 54,
"city_code": "101230902",
"city_name": "顺昌"
},
{
"_id": 484,
"id": 543,
"pid": 54,
"city_code": "101230906",
"city_name": "浦城"
},
{
"_id": 485,
"id": 544,
"pid": 54,
"city_code": "101230903",
"city_name": "光泽"
},
{
"_id": 486,
"id": 545,
"pid": 54,
"city_code": "101230908",
"city_name": "松溪"
},
{
"_id": 487,
"id": 546,
"pid": 54,
"city_code": "101230909",
"city_name": "政和"
},
{
"_id": 488,
"id": 548,
"pid": 55,
"city_code": "101230306",
"city_name": "福安"
},
{
"_id": 489,
"id": 549,
"pid": 55,
"city_code": "101230308",
"city_name": "福鼎"
},
{
"_id": 490,
"id": 550,
"pid": 55,
"city_code": "101230303",
"city_name": "霞浦"
},
{
"_id": 491,
"id": 551,
"pid": 55,
"city_code": "101230302",
"city_name": "古田"
},
{
"_id": 492,
"id": 552,
"pid": 55,
"city_code": "101230309",
"city_name": "屏南"
},
{
"_id": 493,
"id": 553,
"pid": 55,
"city_code": "101230304",
"city_name": "寿宁"
},
{
"_id": 494,
"id": 554,
"pid": 55,
"city_code": "101230305",
"city_name": "周宁"
},
{
"_id": 495,
"id": 555,
"pid": 55,
"city_code": "101230307",
"city_name": "柘荣"
},
{
"_id": 496,
"id": 556,
"pid": 56,
"city_code": "101230407",
"city_name": "城厢"
},
{
"_id": 497,
"id": 557,
"pid": 56,
"city_code": "101230404",
"city_name": "涵江"
},
{
"_id": 498,
"id": 558,
"pid": 56,
"city_code": "101230406",
"city_name": "荔城"
},
{
"_id": 499,
"id": 559,
"pid": 56,
"city_code": "101230405",
"city_name": "秀屿"
},
{
"_id": 500,
"id": 560,
"pid": 56,
"city_code": "101230402",
"city_name": "仙游"
},
{
"_id": 501,
"id": 566,
"pid": 57,
"city_code": "101230510",
"city_name": "石狮"
},
{
"_id": 502,
"id": 567,
"pid": 57,
"city_code": "101230509",
"city_name": "晋江"
},
{
"_id": 503,
"id": 568,
"pid": 57,
"city_code": "101230506",
"city_name": "南安"
},
{
"_id": 504,
"id": 569,
"pid": 57,
"city_code": "101230508",
"city_name": "惠安"
},
{
"_id": 505,
"id": 570,
"pid": 57,
"city_code": "101230502",
"city_name": "安溪"
},
{
"_id": 506,
"id": 571,
"pid": 57,
"city_code": "101230504",
"city_name": "永春"
},
{
"_id": 507,
"id": 572,
"pid": 57,
"city_code": "101230505",
"city_name": "德化"
},
{
"_id": 508,
"id": 576,
"pid": 58,
"city_code": "101230810",
"city_name": "永安"
},
{
"_id": 509,
"id": 577,
"pid": 58,
"city_code": "101230807",
"city_name": "明溪"
},
{
"_id": 510,
"id": 578,
"pid": 58,
"city_code": "101230803",
"city_name": "清流"
},
{
"_id": 511,
"id": 579,
"pid": 58,
"city_code": "101230802",
"city_name": "宁化"
},
{
"_id": 512,
"id": 580,
"pid": 58,
"city_code": "101230811",
"city_name": "大田"
},
{
"_id": 513,
"id": 581,
"pid": 58,
"city_code": "101230809",
"city_name": "尤溪"
},
{
"_id": 514,
"id": 582,
"pid": 58,
"city_code": "101230808",
"city_name": "沙"
},
{
"_id": 515,
"id": 583,
"pid": 58,
"city_code": "101230805",
"city_name": "将乐"
},
{
"_id": 516,
"id": 584,
"pid": 58,
"city_code": "101230804",
"city_name": "泰宁"
},
{
"_id": 517,
"id": 585,
"pid": 58,
"city_code": "101230806",
"city_name": "建宁"
},
{
"_id": 518,
"id": 590,
"pid": 59,
"city_code": "101230202",
"city_name": "同安"
},
{
"_id": 519,
"id": 594,
"pid": 60,
"city_code": "101230605",
"city_name": "龙海"
},
{
"_id": 520,
"id": 595,
"pid": 60,
"city_code": "101230609",
"city_name": "云霄"
},
{
"_id": 521,
"id": 596,
"pid": 60,
"city_code": "101230606",
"city_name": "漳浦"
},
{
"_id": 522,
"id": 597,
"pid": 60,
"city_code": "101230607",
"city_name": "诏安"
},
{
"_id": 523,
"id": 598,
"pid": 60,
"city_code": "101230602",
"city_name": "长泰"
},
{
"_id": 524,
"id": 599,
"pid": 60,
"city_code": "101230608",
"city_name": "东山"
},
{
"_id": 525,
"id": 600,
"pid": 60,
"city_code": "101230603",
"city_name": "南靖"
},
{
"_id": 526,
"id": 601,
"pid": 60,
"city_code": "101230604",
"city_name": "平和"
},
{
"_id": 527,
"id": 602,
"pid": 60,
"city_code": "101230610",
"city_name": "华安"
},
{
"_id": 528,
"id": 603,
"pid": 61,
"city_code": "101160102",
"city_name": "皋兰"
},
{
"_id": 529,
"id": 609,
"pid": 61,
"city_code": "101160103",
"city_name": "永登"
},
{
"_id": 530,
"id": 610,
"pid": 61,
"city_code": "101160104",
"city_name": "榆中"
},
{
"_id": 531,
"id": 611,
"pid": 62,
"city_code": "101161301",
"city_name": "白银"
},
{
"_id": 532,
"id": 612,
"pid": 62,
"city_code": "101161304",
"city_name": "平川"
},
{
"_id": 533,
"id": 613,
"pid": 62,
"city_code": "101161303",
"city_name": "会宁"
},
{
"_id": 534,
"id": 614,
"pid": 62,
"city_code": "101161305",
"city_name": "景泰"
},
{
"_id": 535,
"id": 615,
"pid": 62,
"city_code": "101161302",
"city_name": "靖远"
},
{
"_id": 536,
"id": 616,
"pid": 63,
"city_code": "101160205",
"city_name": "临洮"
},
{
"_id": 537,
"id": 617,
"pid": 63,
"city_code": "101160203",
"city_name": "陇西"
},
{
"_id": 538,
"id": 618,
"pid": 63,
"city_code": "101160202",
"city_name": "通渭"
},
{
"_id": 539,
"id": 619,
"pid": 63,
"city_code": "101160204",
"city_name": "渭源"
},
{
"_id": 540,
"id": 620,
"pid": 63,
"city_code": "101160206",
"city_name": "漳"
},
{
"_id": 541,
"id": 621,
"pid": 63,
"city_code": "101160207",
"city_name": "岷"
},
{
"_id": 542,
"id": 624,
"pid": 64,
"city_code": "101161201",
"city_name": "合作"
},
{
"_id": 543,
"id": 625,
"pid": 64,
"city_code": "101161202",
"city_name": "临潭"
},
{
"_id": 544,
"id": 626,
"pid": 64,
"city_code": "101161203",
"city_name": "卓尼"
},
{
"_id": 545,
"id": 627,
"pid": 64,
"city_code": "101161204",
"city_name": "舟曲"
},
{
"_id": 546,
"id": 628,
"pid": 64,
"city_code": "101161205",
"city_name": "迭部"
},
{
"_id": 547,
"id": 629,
"pid": 64,
"city_code": "101161206",
"city_name": "玛曲"
},
{
"_id": 548,
"id": 630,
"pid": 64,
"city_code": "101161207",
"city_name": "碌曲"
},
{
"_id": 549,
"id": 631,
"pid": 64,
"city_code": "101161208",
"city_name": "夏河"
},
{
"_id": 550,
"id": 634,
"pid": 66,
"city_code": "101160602",
"city_name": "永昌"
},
{
"_id": 551,
"id": 636,
"pid": 67,
"city_code": "101160807",
"city_name": "玉门"
},
{
"_id": 552,
"id": 637,
"pid": 67,
"city_code": "101160808",
"city_name": "敦煌"
},
{
"_id": 553,
"id": 638,
"pid": 67,
"city_code": "101160803",
"city_name": "金塔"
},
{
"_id": 554,
"id": 639,
"pid": 67,
"city_code": "101160805",
"city_name": "瓜州"
},
{
"_id": 555,
"id": 640,
"pid": 67,
"city_code": "101160806",
"city_name": "肃北"
},
{
"_id": 556,
"id": 641,
"pid": 67,
"city_code": "101160804",
"city_name": "阿克塞"
},
{
"_id": 557,
"id": 642,
"pid": 68,
"city_code": "101161101",
"city_name": "临夏"
},
{
"_id": 558,
"id": 643,
"pid": 68,
"city_code": "101161101",
"city_name": "临夏"
},
{
"_id": 559,
"id": 644,
"pid": 68,
"city_code": "101161102",
"city_name": "康乐"
},
{
"_id": 560,
"id": 645,
"pid": 68,
"city_code": "101161103",
"city_name": "永靖"
},
{
"_id": 561,
"id": 646,
"pid": 68,
"city_code": "101161104",
"city_name": "广河"
},
{
"_id": 562,
"id": 647,
"pid": 68,
"city_code": "101161105",
"city_name": "和政"
},
{
"_id": 563,
"id": 648,
"pid": 68,
"city_code": "101161106",
"city_name": "东乡族自治"
},
{
"_id": 564,
"id": 649,
"pid": 68,
"city_code": "101161107",
"city_name": "积石山"
},
{
"_id": 565,
"id": 650,
"pid": 69,
"city_code": "101161002",
"city_name": "成"
},
{
"_id": 566,
"id": 651,
"pid": 69,
"city_code": "101161008",
"city_name": "徽"
},
{
"_id": 567,
"id": 652,
"pid": 69,
"city_code": "101161005",
"city_name": "康"
},
{
"_id": 568,
"id": 653,
"pid": 69,
"city_code": "101161007",
"city_name": "礼"
},
{
"_id": 569,
"id": 654,
"pid": 69,
"city_code": "101161009",
"city_name": "两当"
},
{
"_id": 570,
"id": 655,
"pid": 69,
"city_code": "101161003",
"city_name": "文"
},
{
"_id": 571,
"id": 656,
"pid": 69,
"city_code": "101161006",
"city_name": "西和"
},
{
"_id": 572,
"id": 657,
"pid": 69,
"city_code": "101161004",
"city_name": "宕昌"
},
{
"_id": 573,
"id": 658,
"pid": 69,
"city_code": "101161001",
"city_name": "武都"
},
{
"_id": 574,
"id": 659,
"pid": 70,
"city_code": "101160304",
"city_name": "崇信"
},
{
"_id": 575,
"id": 660,
"pid": 70,
"city_code": "101160305",
"city_name": "华亭"
},
{
"_id": 576,
"id": 661,
"pid": 70,
"city_code": "101160307",
"city_name": "静宁"
},
{
"_id": 577,
"id": 662,
"pid": 70,
"city_code": "101160303",
"city_name": "灵台"
},
{
"_id": 578,
"id": 663,
"pid": 70,
"city_code": "1011
gitextract_p348k3l_/
├── .gitignore
├── LICENSE.md
├── README.md
├── doc/
│ └── OLD_README.md
├── pom.xml
└── src/
├── main/
│ ├── java/
│ │ ├── IdentifyCommand/
│ │ │ ├── CheckCommandType.java
│ │ │ └── PreProcessMessage.java
│ │ ├── WechatBot.java
│ │ ├── api/
│ │ │ ├── ChatApi.java
│ │ │ ├── EveryDayHelloApi.java
│ │ │ ├── HelpMsg.java
│ │ │ ├── NewsApi.java
│ │ │ ├── RubbishApi.java
│ │ │ ├── WeatherApi.java
│ │ │ ├── ZhihuHotApi.java
│ │ │ └── entity/
│ │ │ └── RubbishToolBoxResponseEntity.java
│ │ ├── cache/
│ │ │ └── redis/
│ │ │ ├── NewsCacheFactory.java
│ │ │ ├── RubbishLinkCacheFactory.java
│ │ │ ├── RubbishTypeCacheFactory.java
│ │ │ ├── WeatherCacheFactory.java
│ │ │ ├── ZhihuHotCacheFactory.java
│ │ │ ├── entity/
│ │ │ │ ├── NewsCacheEntity.java
│ │ │ │ ├── RubbishCacheEntity.java
│ │ │ │ ├── RubbishLinkCacheEntity.java
│ │ │ │ ├── WeatherCacheEntity.java
│ │ │ │ └── ZhihuHotCacheEntity.java
│ │ │ └── provider/
│ │ │ ├── BaseRedisCache.java
│ │ │ ├── JedisPoolUtil.java
│ │ │ └── RCacheEntity.java
│ │ ├── config/
│ │ │ ├── GlobalConfig.java
│ │ │ ├── QingWeatherCityConfig.java
│ │ │ └── RedisConfig.java
│ │ ├── cons/
│ │ │ └── WxMsg.java
│ │ ├── enums/
│ │ │ ├── CommandType.java
│ │ │ ├── FriendType.java
│ │ │ ├── GroupType.java
│ │ │ └── RubbishType.java
│ │ ├── main/
│ │ │ ├── WechatBotClient.java
│ │ │ ├── facade/
│ │ │ │ ├── DealMessage.java
│ │ │ │ └── DoCommand.java
│ │ │ └── service/
│ │ │ ├── everydayHelloMsg/
│ │ │ │ └── EveryDayHelloWhiteList.java
│ │ │ ├── friendMsg/
│ │ │ │ ├── CheckFriendType.java
│ │ │ │ └── FriendChat.java
│ │ │ └── groupMsg/
│ │ │ ├── CheckGroupType.java
│ │ │ ├── GroupChat.java
│ │ │ └── GroupTextCommand.java
│ │ ├── robot/
│ │ │ ├── AToolBox/
│ │ │ │ ├── ToolBoxRubbish.java
│ │ │ │ └── entity/
│ │ │ │ └── ToolBoxRubbishContentEntity.java
│ │ │ ├── Ciba/
│ │ │ │ ├── CibaEveryDayHello.java
│ │ │ │ └── entity/
│ │ │ │ └── CibaEveryDayHelloEntity.java
│ │ │ ├── QingyunkeRobot/
│ │ │ │ ├── QingyunkeRobot.java
│ │ │ │ ├── QingyunkeWeather/
│ │ │ │ │ ├── QingWeather.java
│ │ │ │ │ ├── QingWeatherCityId.java
│ │ │ │ │ └── entity/
│ │ │ │ │ ├── QingWeatherCityEntity.java
│ │ │ │ │ └── QingWeatherEntity.java
│ │ │ │ └── entity/
│ │ │ │ └── QingyunkeResponseEntity.java
│ │ │ ├── RollToolsApi/
│ │ │ │ ├── RollNews.java
│ │ │ │ ├── RollWeather.java
│ │ │ │ └── entity/
│ │ │ │ ├── RollNewsContentEntity.java
│ │ │ │ ├── RollNewsDetailsEntity.java
│ │ │ │ ├── RollNewsEntity.java
│ │ │ │ └── RollWeatherEntity.java
│ │ │ ├── RubbishClassificationApp/
│ │ │ │ └── RubbishApp.java
│ │ │ └── Zhihu/
│ │ │ ├── ZhihuHot.java
│ │ │ └── entity/
│ │ │ ├── ZhihuHotContentEntity.java
│ │ │ ├── ZhihuHotDetailEntity.java
│ │ │ └── ZhihuHotEntity.java
│ │ ├── schedule/
│ │ │ ├── EverydayHelloSchedule.java
│ │ │ ├── base/
│ │ │ │ └── BaseScheduleTask.java
│ │ │ └── task/
│ │ │ ├── FriendEverydayTask.java
│ │ │ └── GroupEverydayTask.java
│ │ └── utils/
│ │ ├── AtMeMsg.java
│ │ ├── DateUtil.java
│ │ ├── GroupMsgUtil.java
│ │ ├── HttpRequestUtil.java
│ │ ├── QRCodeUtil.java
│ │ ├── ScheduleUtil.java
│ │ └── ThreadPoolUtil.java
│ └── resources/
│ ├── city.json
│ ├── config.properties
│ └── redis.properties
└── test/
└── java/
├── CacheTest.java
├── HttpTest.java
└── city.json
SYMBOL INDEX (267 symbols across 75 files)
FILE: src/main/java/IdentifyCommand/CheckCommandType.java
class CheckCommandType (line 12) | public class CheckCommandType {
method CheckCommandType (line 16) | private CheckCommandType() {
method getInstance (line 19) | public static CheckCommandType getInstance() {
method checkCommandType (line 31) | public CommandType checkCommandType(String content) {
method isWeatherCommand (line 59) | private boolean isWeatherCommand(String content) {
method isNewsCommand (line 63) | private boolean isNewsCommand(String content) {
method isRubbishCommand (line 67) | private boolean isRubbishCommand(String content) {
method isZhihuHotCommand (line 71) | private boolean isZhihuHotCommand(String content) {
method isDiDiCommand (line 75) | private boolean isDiDiCommand(String content) {
method isVoteCommand (line 79) | private boolean isVoteCommand(String content) {
FILE: src/main/java/IdentifyCommand/PreProcessMessage.java
class PreProcessMessage (line 14) | @Slf4j
method isCommand (line 37) | public static boolean isCommand(WXMessage message) {
method startWithCommandPrefix (line 45) | private static boolean startWithCommandPrefix(String content) {
method getCommandPrefix (line 55) | public static String getCommandPrefix() {
method getCommandPrefix (line 59) | public static String getCommandPrefix(boolean isEnglish) {
method removeCommandFix (line 66) | public static void removeCommandFix(WXMessage message) {
FILE: src/main/java/WechatBot.java
class WechatBot (line 7) | public class WechatBot {
method main (line 8) | public static void main(String[] args) {
FILE: src/main/java/api/ChatApi.java
class ChatApi (line 14) | @Slf4j
method chat (line 19) | public static String chat(WXMessage message) {
FILE: src/main/java/api/EveryDayHelloApi.java
class EveryDayHelloApi (line 15) | @Slf4j
method getGroupHelloMsg (line 35) | public static String getGroupHelloMsg() {
method getFriendHelloMsg (line 50) | public static String getFriendHelloMsg() {
method getMsg (line 56) | private static String getMsg() {
FILE: src/main/java/api/HelpMsg.java
class HelpMsg (line 13) | public class HelpMsg {
method getHelpMsg (line 17) | public static String getHelpMsg() {
FILE: src/main/java/api/NewsApi.java
class NewsApi (line 16) | @Slf4j
method dealNewsMsg (line 23) | public static String dealNewsMsg(WXMessage message) {
method getTodayNews (line 34) | public static String getTodayNews(@NonNull String keyword) {
method getTodayTotalNews (line 41) | private static String getTodayTotalNews() {
FILE: src/main/java/api/RubbishApi.java
class RubbishApi (line 25) | @Slf4j
method dealRubbishMsg (line 39) | public static String dealRubbishMsg(WXMessage message) {
method classifyRubbish (line 53) | public static String classifyRubbish(String rubbish) {
method checkRubbishType (line 71) | private static RubbishType checkRubbishType(String rubbish, RubbishToo...
method getRubbishTypeFromApi (line 108) | private static RubbishType getRubbishTypeFromApi(String rubbish, Rubbi...
method getRubbishTypeString (line 124) | private static String getRubbishTypeString(String rubbish, @NonNull Ru...
method getRubbishTypeTip (line 138) | private static String getRubbishTypeTip(RubbishType type, @NonNull Rub...
method getLinkRubbishList (line 166) | private static String getLinkRubbishList(String rubbish) {
method getLinkRubbishListFromApi (line 190) | private static String getLinkRubbishListFromApi(String rubbish) {
FILE: src/main/java/api/WeatherApi.java
class WeatherApi (line 18) | @Slf4j
method dealWeatherMsg (line 37) | public static String dealWeatherMsg(WXMessage message) {
method getFastWeatherCommand (line 57) | private static String getFastWeatherCommand(WXMessage message) {
method getWeatherByKeyword (line 70) | public static String getWeatherByKeyword(String keyword) {
method getWeatherByCityName (line 89) | public static String getWeatherByCityName(String cityName) {
method getWeatherFromApi (line 111) | private static String getWeatherFromApi(String cityName) {
FILE: src/main/java/api/ZhihuHotApi.java
class ZhihuHotApi (line 14) | public class ZhihuHotApi {
method dealZhihuHotMsg (line 17) | public static String dealZhihuHotMsg(WXMessage message) {
FILE: src/main/java/api/entity/RubbishToolBoxResponseEntity.java
class RubbishToolBoxResponseEntity (line 15) | @Data
method RubbishToolBoxResponseEntity (line 24) | public RubbishToolBoxResponseEntity(String rubbish) {
method getResult (line 28) | public String getResult() {
FILE: src/main/java/cache/redis/NewsCacheFactory.java
class NewsCacheFactory (line 15) | public class NewsCacheFactory {
method getNewsCacheEntity (line 27) | public static NewsCacheEntity getNewsCacheEntity(String typeId, String...
method getNewsCacheEntity (line 37) | public static NewsCacheEntity getNewsCacheEntity(String typeId, int li...
method getSingleNewsCacheEntity (line 47) | public static NewsCacheEntity getSingleNewsCacheEntity(String newsId) {
FILE: src/main/java/cache/redis/RubbishLinkCacheFactory.java
class RubbishLinkCacheFactory (line 11) | public class RubbishLinkCacheFactory {
method getRubbishLinkCache (line 15) | public static RubbishLinkCacheEntity getRubbishLinkCache(String rubbis...
FILE: src/main/java/cache/redis/RubbishTypeCacheFactory.java
class RubbishTypeCacheFactory (line 13) | public class RubbishTypeCacheFactory {
method getRubbishCacheEntity (line 21) | public static RubbishCacheEntity getRubbishCacheEntity(@NonNull String...
FILE: src/main/java/cache/redis/WeatherCacheFactory.java
class WeatherCacheFactory (line 16) | public class WeatherCacheFactory {
method getWeatherCacheEntity (line 23) | public static WeatherCacheEntity getWeatherCacheEntity(String cityName...
method getWeatherCacheEntity (line 32) | public static WeatherCacheEntity getWeatherCacheEntity(String cityName) {
FILE: src/main/java/cache/redis/ZhihuHotCacheFactory.java
class ZhihuHotCacheFactory (line 15) | public class ZhihuHotCacheFactory {
method getZhihuHotCacheEntity (line 28) | public static ZhihuHotCacheEntity getZhihuHotCacheEntity(String date, ...
method getZhihuHotCacheEntity (line 37) | public static ZhihuHotCacheEntity getZhihuHotCacheEntity(int limit) {
method getSingleZhihuHotCacheEntity (line 46) | public static ZhihuHotCacheEntity getSingleZhihuHotCacheEntity(long ne...
FILE: src/main/java/cache/redis/entity/NewsCacheEntity.java
class NewsCacheEntity (line 11) | public class NewsCacheEntity extends RCacheEntity {
method NewsCacheEntity (line 12) | public NewsCacheEntity(KeyBuilder keyBuilder) {
method NewsCacheEntity (line 16) | public NewsCacheEntity(KeyBuilder keyBuilder, int expireSeconds) {
FILE: src/main/java/cache/redis/entity/RubbishCacheEntity.java
class RubbishCacheEntity (line 12) | public class RubbishCacheEntity extends RCacheEntity {
method RubbishCacheEntity (line 14) | public RubbishCacheEntity(KeyBuilder keyBuilder) {
method RubbishCacheEntity (line 18) | public RubbishCacheEntity(KeyBuilder keyBuilder, int expireSeconds) {
method getRubbishType (line 22) | public RubbishType getRubbishType() {
method setValue (line 31) | public RubbishCacheEntity setValue(RubbishType rubbishType) {
FILE: src/main/java/cache/redis/entity/RubbishLinkCacheEntity.java
class RubbishLinkCacheEntity (line 11) | public class RubbishLinkCacheEntity extends RCacheEntity {
method RubbishLinkCacheEntity (line 13) | public RubbishLinkCacheEntity(KeyBuilder keyBuilder) {
method RubbishLinkCacheEntity (line 17) | public RubbishLinkCacheEntity(KeyBuilder keyBuilder, int expireSeconds) {
FILE: src/main/java/cache/redis/entity/WeatherCacheEntity.java
class WeatherCacheEntity (line 11) | public class WeatherCacheEntity extends RCacheEntity {
method WeatherCacheEntity (line 12) | public WeatherCacheEntity(KeyBuilder keyBuilder) {
method WeatherCacheEntity (line 16) | public WeatherCacheEntity(KeyBuilder keyBuilder, int expireSeconds) {
FILE: src/main/java/cache/redis/entity/ZhihuHotCacheEntity.java
class ZhihuHotCacheEntity (line 11) | public class ZhihuHotCacheEntity extends RCacheEntity {
method ZhihuHotCacheEntity (line 12) | public ZhihuHotCacheEntity(KeyBuilder keyBuilder) {
method ZhihuHotCacheEntity (line 16) | public ZhihuHotCacheEntity(KeyBuilder keyBuilder, int expireSeconds) {
FILE: src/main/java/cache/redis/provider/BaseRedisCache.java
class BaseRedisCache (line 11) | public class BaseRedisCache {
method getInstance (line 15) | public static BaseRedisCache getInstance() {
method BaseRedisCache (line 26) | private BaseRedisCache() {
method setex (line 32) | public boolean setex(String key, String value, int seconds) {
method set (line 39) | public boolean set(String key, String value) {
method get (line 46) | public String get(String key) {
method del (line 53) | public boolean del(String key) {
FILE: src/main/java/cache/redis/provider/JedisPoolUtil.java
class JedisPoolUtil (line 15) | public class JedisPoolUtil {
method getJedis (line 32) | public static Jedis getJedis() {
method createJedisPool (line 42) | private static void createJedisPool() {
method poolInit (line 54) | private static synchronized void poolInit() {
FILE: src/main/java/cache/redis/provider/RCacheEntity.java
class RCacheEntity (line 16) | public class RCacheEntity {
method save (line 33) | public boolean save() {
method get (line 44) | public String get() {
method del (line 48) | public boolean del() {
method RCacheEntity (line 53) | public RCacheEntity(KeyBuilder keyBuilder) {
method RCacheEntity (line 57) | public RCacheEntity(KeyBuilder keyBuilder, int expireSeconds) {
method setValue (line 63) | public RCacheEntity setValue(String value) {
method getKey (line 68) | private String getKey() {
class KeyBuilder (line 73) | public static class KeyBuilder {
method KeyBuilder (line 80) | public KeyBuilder(String name) {
method addParam (line 84) | public KeyBuilder addParam(String name, Object object) {
method build (line 89) | private String build() {
FILE: src/main/java/config/GlobalConfig.java
class GlobalConfig (line 10) | @Slf4j
method getValue (line 24) | public static String getValue(String key, String defaultValue) {
FILE: src/main/java/config/QingWeatherCityConfig.java
class QingWeatherCityConfig (line 12) | @Slf4j
method QingWeatherCityConfig (line 22) | private QingWeatherCityConfig() {
method getInstance (line 42) | public static QingWeatherCityConfig getInstance() {
FILE: src/main/java/config/RedisConfig.java
class RedisConfig (line 10) | @Slf4j
method getValue (line 24) | public static String getValue(String key, String defaultValue) {
method isRedisEnable (line 32) | public static boolean isRedisEnable() {
method isRedisNotEnable (line 36) | public static boolean isRedisNotEnable() {
FILE: src/main/java/cons/WxMsg.java
class WxMsg (line 9) | public class WxMsg {
FILE: src/main/java/enums/CommandType.java
type CommandType (line 12) | @Getter
FILE: src/main/java/enums/FriendType.java
type FriendType (line 12) | @Getter
FILE: src/main/java/enums/GroupType.java
type GroupType (line 6) | @Getter
FILE: src/main/java/enums/RubbishType.java
type RubbishType (line 11) | public enum RubbishType {
method findByValue (line 31) | public static RubbishType findByValue(int value) {
method RubbishType (line 51) | RubbishType(int value, String name) {
FILE: src/main/java/main/WechatBotClient.java
class WechatBotClient (line 29) | @Slf4j
method onQRCode (line 50) | @Override
method onLogin (line 56) | @Override
method onMessage (line 61) | @Override
method onContact (line 104) | @Override
method run (line 113) | public static void run(String[] args) {
FILE: src/main/java/main/facade/DealMessage.java
class DealMessage (line 12) | @Slf4j
method dealGroupTextMsg (line 15) | public static String dealGroupTextMsg(WXMessage message) {
method dealFriendTextMsg (line 35) | public static String dealFriendTextMsg(WXMessage message) {
FILE: src/main/java/main/facade/DoCommand.java
class DoCommand (line 14) | @Slf4j
method doGroupTextCommand (line 17) | public static String doGroupTextCommand(WXMessage message) {
FILE: src/main/java/main/service/everydayHelloMsg/EveryDayHelloWhiteList.java
class EveryDayHelloWhiteList (line 20) | @Slf4j
method EveryDayHelloWhiteList (line 30) | private EveryDayHelloWhiteList() {
method getInstance (line 67) | public static EveryDayHelloWhiteList getInstance() {
FILE: src/main/java/main/service/friendMsg/CheckFriendType.java
class CheckFriendType (line 18) | @Slf4j
method checkFriendType (line 37) | public static FriendType checkFriendType(String friendName) {
FILE: src/main/java/main/service/friendMsg/FriendChat.java
class FriendChat (line 15) | @Slf4j
method dealFriendMsg (line 22) | public static String dealFriendMsg(WXMessage message) {
method autoReplyFriend (line 36) | private static String autoReplyFriend(WXMessage message) {
FILE: src/main/java/main/service/groupMsg/CheckGroupType.java
class CheckGroupType (line 18) | @Slf4j
method checkGroupType (line 61) | public static GroupType checkGroupType(String from) {
FILE: src/main/java/main/service/groupMsg/GroupChat.java
class GroupChat (line 8) | @Slf4j
method GroupChat (line 13) | private GroupChat() {
method getInstance (line 16) | public static GroupChat getInstance() {
method dealGroupChatMsg (line 28) | public String dealGroupChatMsg(WXMessage message) {
method dealChatMsg (line 43) | private String dealChatMsg(WXMessage message) {
FILE: src/main/java/main/service/groupMsg/GroupTextCommand.java
class GroupTextCommand (line 15) | public class GroupTextCommand {
method GroupTextCommand (line 19) | private GroupTextCommand() {
method getInstance (line 22) | public static GroupTextCommand getInstance() {
method doGroupCommand (line 33) | public String doGroupCommand(WXMessage message) {
method isFastCommand (line 62) | private boolean isFastCommand(String content) {
method doGroupHelp (line 67) | private String doGroupHelp(WXMessage message) {
method doGroupWeather (line 77) | private String doGroupWeather(WXMessage message) {
method doGroupNews (line 87) | private String doGroupNews(WXMessage message) {
method doGroupZhihuHot (line 96) | private String doGroupZhihuHot(WXMessage message) {
method doGroupRubbish (line 106) | private String doGroupRubbish(WXMessage message) {
method doGroupDiDi (line 117) | private String doGroupDiDi(WXMessage message) {
method doGroupVote (line 127) | private String doGroupVote(WXMessage message){
FILE: src/main/java/robot/AToolBox/ToolBoxRubbish.java
class ToolBoxRubbish (line 29) | @Slf4j
method getRubbishResult (line 40) | private static String getRubbishResult(@NonNull String rubbish) {
method getRubbishType (line 54) | public static RubbishType getRubbishType(String rubbish, RubbishToolBo...
method getType (line 96) | private static RubbishType getType(String stringType) {
method cacheAllResult (line 114) | private static void cacheAllResult(Map<String, Map<String, String>> ma...
method cacheLinkRubbish (line 124) | private static void cacheLinkRubbish(String rubbish, String linkRubbis...
method getLinkRubbish (line 129) | public static String getLinkRubbish(String rubbish) {
method getLinkRubbishList (line 153) | private static String getLinkRubbishList(String rubbish, Map<String, M...
FILE: src/main/java/robot/AToolBox/entity/ToolBoxRubbishContentEntity.java
class ToolBoxRubbishContentEntity (line 11) | @Data
FILE: src/main/java/robot/Ciba/CibaEveryDayHello.java
class CibaEveryDayHello (line 14) | public class CibaEveryDayHello {
method getCibaEveryday (line 18) | public static String getCibaEveryday() {
FILE: src/main/java/robot/Ciba/entity/CibaEveryDayHelloEntity.java
class CibaEveryDayHelloEntity (line 15) | @Data
method getSentence (line 32) | public String getSentence() {
class CibaEveryDayHelloTags (line 38) | @Data
FILE: src/main/java/robot/QingyunkeRobot/QingyunkeRobot.java
class QingyunkeRobot (line 13) | public class QingyunkeRobot {
method getResponse (line 19) | public static String getResponse(String keyWord) {
method replaceBr (line 39) | private static String replaceBr(String content) {
FILE: src/main/java/robot/QingyunkeRobot/QingyunkeWeather/QingWeather.java
class QingWeather (line 9) | public class QingWeather {
method getWeatherByCityId (line 13) | public static String getWeatherByCityId(String cityId) {
method getWeatherByKeyword (line 26) | public static String getWeatherByKeyword(String keyWord) {
method getWeatherByCityName (line 34) | public static String getWeatherByCityName(String cityName) {
FILE: src/main/java/robot/QingyunkeRobot/QingyunkeWeather/QingWeatherCityId.java
class QingWeatherCityId (line 11) | public class QingWeatherCityId {
method QingWeatherCityId (line 15) | private QingWeatherCityId() {
method getInstance (line 19) | public static QingWeatherCityId getInstance() {
method getCityId (line 36) | public String getCityId(String cityName) {
FILE: src/main/java/robot/QingyunkeRobot/QingyunkeWeather/entity/QingWeatherCityEntity.java
class QingWeatherCityEntity (line 5) | @Data
FILE: src/main/java/robot/QingyunkeRobot/QingyunkeWeather/entity/QingWeatherEntity.java
class QingWeatherEntity (line 9) | @Data
method isValid (line 19) | public boolean isValid() {
method getWeather (line 23) | public String getWeather() {
class CityInfo (line 36) | @Data
method getCityName (line 43) | String getCityName() {
class WeatherData (line 58) | @Data
method toString (line 70) | @Override
class OtherDay (line 81) | @Data
method getWeather (line 96) | String getWeather() {
FILE: src/main/java/robot/QingyunkeRobot/entity/QingyunkeResponseEntity.java
class QingyunkeResponseEntity (line 6) | public class QingyunkeResponseEntity {
method isValid (line 13) | public boolean isValid(){
method getCode (line 17) | public int getCode() {
method setCode (line 21) | public void setCode(int code) {
method getContent (line 25) | public String getContent() {
method setContent (line 29) | public void setContent(String content) {
FILE: src/main/java/robot/RollToolsApi/RollNews.java
class RollNews (line 23) | @Slf4j
method getTodayTotalNews (line 32) | public static String getTodayTotalNews(String typeId, int limit) {
FILE: src/main/java/robot/RollToolsApi/RollWeather.java
class RollWeather (line 9) | public class RollWeather {
method getWeatherByKeyword (line 13) | public static String getWeatherByKeyword(String keyword) {
method getWeatherByCityName (line 22) | public static String getWeatherByCityName(String cityName) {
FILE: src/main/java/robot/RollToolsApi/entity/RollNewsContentEntity.java
class RollNewsContentEntity (line 13) | @Data
FILE: src/main/java/robot/RollToolsApi/entity/RollNewsDetailsEntity.java
class RollNewsDetailsEntity (line 11) | @Data
FILE: src/main/java/robot/RollToolsApi/entity/RollNewsEntity.java
class RollNewsEntity (line 18) | @Data
method isInValid (line 32) | public boolean isInValid() {
method getTodayNews (line 36) | public String getTodayNews() {
method getTodayNews (line 40) | public String getTodayNews(int maxSize) {
FILE: src/main/java/robot/RollToolsApi/entity/RollWeatherEntity.java
class RollWeatherEntity (line 6) | @Data
method isValid (line 17) | public boolean isValid() {
method getWeather (line 21) | public String getWeather() {
method getWeatherDefaultNull (line 25) | public String getWeatherDefaultNull() {
class RollWeatherData (line 30) | @Data
method toString (line 41) | @Override
FILE: src/main/java/robot/RubbishClassificationApp/RubbishApp.java
class RubbishApp (line 16) | @Slf4j
method getRubbishType (line 21) | public static RubbishType getRubbishType(String rubbish) {
FILE: src/main/java/robot/Zhihu/ZhihuHot.java
class ZhihuHot (line 26) | @Slf4j
method getZhihuHot (line 35) | public static String getZhihuHot() {
method getSingleZhihuHot (line 65) | public static String getSingleZhihuHot(int index) {
FILE: src/main/java/robot/Zhihu/entity/ZhihuHotContentEntity.java
class ZhihuHotContentEntity (line 11) | @Data
FILE: src/main/java/robot/Zhihu/entity/ZhihuHotDetailEntity.java
class ZhihuHotDetailEntity (line 12) | @Data
method getResult (line 24) | public String getResult() {
FILE: src/main/java/robot/Zhihu/entity/ZhihuHotEntity.java
class ZhihuHotEntity (line 14) | @Data
method isValid (line 19) | private boolean isValid() {
method getContent (line 23) | public String getContent(int limit) {
FILE: src/main/java/schedule/EverydayHelloSchedule.java
class EverydayHelloSchedule (line 21) | @Slf4j
method startGroupEverydaySchedule (line 55) | public static void startGroupEverydaySchedule() {
FILE: src/main/java/schedule/base/BaseScheduleTask.java
class BaseScheduleTask (line 18) | @Slf4j
method run (line 26) | @Override
method process (line 40) | protected abstract void process();
FILE: src/main/java/schedule/task/FriendEverydayTask.java
class FriendEverydayTask (line 17) | @Slf4j
method FriendEverydayTask (line 19) | public FriendEverydayTask() {
method process (line 23) | public void process() {
FILE: src/main/java/schedule/task/GroupEverydayTask.java
class GroupEverydayTask (line 18) | @Slf4j
method GroupEverydayTask (line 20) | public GroupEverydayTask() {
method process (line 24) | public void process() {
FILE: src/main/java/utils/AtMeMsg.java
class AtMeMsg (line 20) | public class AtMeMsg {
method isAtMe (line 32) | public static boolean isAtMe(WXMessage message) {
method atMeFix (line 36) | private static String atMeFix(WXMessage message) {
FILE: src/main/java/utils/DateUtil.java
class DateUtil (line 12) | public class DateUtil {
method addOneDay (line 18) | public static Date addOneDay(Date oldDate) {
method addDate (line 22) | public static Date addDate(Date oldDate, int addDays) {
method getYYMMDDHHMMSSDate (line 29) | public static String getYYMMDDHHMMSSDate(Date date) {
method getCurViewDate (line 38) | public static String getCurViewDate() {
method getViewDate (line 42) | public static String getViewDate(Date date) {
method getCacheFormatDate (line 51) | public static String getCacheFormatDate(Date date) {
method getFormatDate (line 61) | public static String getFormatDate(Date date, String pattern) {
method parseDate (line 70) | public static Date parseDate(String source, String pattern) {
FILE: src/main/java/utils/GroupMsgUtil.java
class GroupMsgUtil (line 13) | public class GroupMsgUtil {
method getUserDisplayOrName (line 15) | public static String getUserDisplayOrName(WXMessage message) {
FILE: src/main/java/utils/HttpRequestUtil.java
class HttpRequestUtil (line 14) | @Slf4j
method doGet (line 17) | public static String doGet(String url) {
method httpRequest (line 25) | private static String httpRequest(String requestUrl, String method) {
FILE: src/main/java/utils/QRCodeUtil.java
class QRCodeUtil (line 9) | public class QRCodeUtil {
method printQRCode (line 14) | public static String printQRCode(String url) {
FILE: src/main/java/utils/ScheduleUtil.java
class ScheduleUtil (line 15) | @Slf4j
method scheduleAtFixedRate (line 18) | public static void scheduleAtFixedRate(@NonNull BaseScheduleTask task,
FILE: src/main/java/utils/ThreadPoolUtil.java
class ThreadPoolUtil (line 13) | @Slf4j
method getCachedPool (line 20) | public static ThreadPoolExecutor getCachedPool() {
method getSchedulePool (line 37) | public static ScheduledThreadPoolExecutor getSchedulePool() {
FILE: src/test/java/CacheTest.java
class CacheTest (line 28) | public class CacheTest {
method main (line 31) | public static void main(String[] args) {
FILE: src/test/java/HttpTest.java
class HttpTest (line 8) | public class HttpTest {
method main (line 11) | public static void main(String[] args) {
Condensed preview — 84 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (852K chars).
[
{
"path": ".gitignore",
"chars": 380,
"preview": ".idea\nassets\ntarget/\n\n# Created by .ignore support plugin (hsz.mobi)\n### Java template\n# Compiled class file\n*.class\n\n# "
},
{
"path": "LICENSE.md",
"chars": 11331,
"preview": " Apache License\n Version 2.0, January 2004\n http://www.apache.or"
},
{
"path": "README.md",
"chars": 2915,
"preview": "## 微信机器人Java版\n\n个人微信(非公众号)微信机器人,根据指令自动回复好友消息、群聊陪聊、查天气、查垃圾分类,基于[ChatApi-WeChat](https://github.com/xuxiaoxiao-xxx/ChatApi-"
},
{
"path": "doc/OLD_README.md",
"chars": 1068,
"preview": "## 微信机器人\n\n自动回复好友消息、群聊陪聊、查询天气,基于[ChatApi-WeChat](https://github.com/xuxiaoxiao-xxx/ChatApi-WeChat)构建。 \n\n---\n\n## TODO\n\n- "
},
{
"path": "pom.xml",
"chars": 2202,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n xmlns:xsi=\"http://www"
},
{
"path": "src/main/java/IdentifyCommand/CheckCommandType.java",
"chars": 2096,
"preview": "package IdentifyCommand;\n\nimport enums.CommandType;\nimport org.apache.commons.lang3.StringUtils;\n\n/**\n * Created by Inte"
},
{
"path": "src/main/java/IdentifyCommand/PreProcessMessage.java",
"chars": 2265,
"preview": "package IdentifyCommand;\n\nimport config.GlobalConfig;\nimport lombok.extern.slf4j.Slf4j;\nimport me.xuxiaoxiao.chatapi.wec"
},
{
"path": "src/main/java/WechatBot.java",
"chars": 211,
"preview": "import main.WechatBotClient;\n\n/**\n * @author scorego <javior@qq.com>\n * @date 2019/9/20 23:30\n */\npublic class WechatBot"
},
{
"path": "src/main/java/api/ChatApi.java",
"chars": 733,
"preview": "package api;\n\nimport config.GlobalConfig;\nimport lombok.extern.slf4j.Slf4j;\nimport me.xuxiaoxiao.chatapi.wechat.entity.m"
},
{
"path": "src/main/java/api/EveryDayHelloApi.java",
"chars": 1956,
"preview": "package api;\n\nimport config.GlobalConfig;\nimport cons.WxMsg;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons"
},
{
"path": "src/main/java/api/HelpMsg.java",
"chars": 966,
"preview": "package api;\n\nimport IdentifyCommand.PreProcessMessage;\nimport config.GlobalConfig;\nimport cons.WxMsg;\n\n/**\n * Created b"
},
{
"path": "src/main/java/api/NewsApi.java",
"chars": 1249,
"preview": "package api;\n\nimport config.RedisConfig;\nimport lombok.NonNull;\nimport lombok.extern.slf4j.Slf4j;\nimport me.xuxiaoxiao.c"
},
{
"path": "src/main/java/api/RubbishApi.java",
"chars": 7104,
"preview": "package api;\n\nimport api.entity.RubbishToolBoxResponseEntity;\nimport cache.redis.RubbishLinkCacheFactory;\nimport cache.r"
},
{
"path": "src/main/java/api/WeatherApi.java",
"chars": 3921,
"preview": "package api;\n\nimport cache.redis.WeatherCacheFactory;\nimport cache.redis.entity.WeatherCacheEntity;\nimport config.Global"
},
{
"path": "src/main/java/api/ZhihuHotApi.java",
"chars": 777,
"preview": "package api;\n\n\nimport config.RedisConfig;\nimport me.xuxiaoxiao.chatapi.wechat.entity.message.WXMessage;\nimport robot.Zhi"
},
{
"path": "src/main/java/api/entity/RubbishToolBoxResponseEntity.java",
"chars": 846,
"preview": "package api.entity;\n\nimport cons.WxMsg;\nimport lombok.Data;\nimport org.apache.commons.lang3.StringUtils;\nimport robot.AT"
},
{
"path": "src/main/java/cache/redis/NewsCacheFactory.java",
"chars": 1708,
"preview": "package cache.redis;\n\nimport cache.redis.entity.NewsCacheEntity;\nimport cache.redis.entity.WeatherCacheEntity;\nimport ut"
},
{
"path": "src/main/java/cache/redis/RubbishLinkCacheFactory.java",
"chars": 581,
"preview": "package cache.redis;\n\nimport cache.redis.entity.RubbishLinkCacheEntity;\n\n/**\n * Created by IntelliJ IDEA.\n *\n * @author "
},
{
"path": "src/main/java/cache/redis/RubbishTypeCacheFactory.java",
"chars": 629,
"preview": "package cache.redis;\n\nimport cache.redis.entity.RubbishCacheEntity;\nimport lombok.NonNull;\n\n/**\n * Created by IntelliJ I"
},
{
"path": "src/main/java/cache/redis/WeatherCacheFactory.java",
"chars": 1143,
"preview": "package cache.redis;\n\n\nimport cache.redis.entity.WeatherCacheEntity;\nimport utils.DateUtil;\n\nimport java.util.Date;\n\n/**"
},
{
"path": "src/main/java/cache/redis/ZhihuHotCacheFactory.java",
"chars": 1752,
"preview": "package cache.redis;\n\nimport cache.redis.entity.WeatherCacheEntity;\nimport cache.redis.entity.ZhihuHotCacheEntity;\nimpor"
},
{
"path": "src/main/java/cache/redis/entity/NewsCacheEntity.java",
"chars": 414,
"preview": "package cache.redis.entity;\n\nimport cache.redis.provider.RCacheEntity;\n\n/**\n * Created by IntelliJ IDEA.\n *\n * @author J"
},
{
"path": "src/main/java/cache/redis/entity/RubbishCacheEntity.java",
"chars": 830,
"preview": "package cache.redis.entity;\n\nimport cache.redis.provider.RCacheEntity;\nimport enums.RubbishType;\n\n/**\n * Created by Inte"
},
{
"path": "src/main/java/cache/redis/entity/RubbishLinkCacheEntity.java",
"chars": 438,
"preview": "package cache.redis.entity;\n\nimport cache.redis.provider.RCacheEntity;\n\n/**\n * Created by IntelliJ IDEA.\n *\n * @author J"
},
{
"path": "src/main/java/cache/redis/entity/WeatherCacheEntity.java",
"chars": 423,
"preview": "package cache.redis.entity;\n\nimport cache.redis.provider.RCacheEntity;\n\n/**\n * Created by IntelliJ IDEA.\n *\n * @author J"
},
{
"path": "src/main/java/cache/redis/entity/ZhihuHotCacheEntity.java",
"chars": 425,
"preview": "package cache.redis.entity;\n\nimport cache.redis.provider.RCacheEntity;\n\n/**\n * Created by IntelliJ IDEA.\n *\n * @author J"
},
{
"path": "src/main/java/cache/redis/provider/BaseRedisCache.java",
"chars": 1455,
"preview": "package cache.redis.provider;\n\nimport redis.clients.jedis.Jedis;\n\n/**\n * Created by IntelliJ IDEA.\n *\n * @author Javior\n"
},
{
"path": "src/main/java/cache/redis/provider/JedisPoolUtil.java",
"chars": 1353,
"preview": "package cache.redis.provider;\n\nimport config.RedisConfig;\nimport org.apache.commons.lang3.StringUtils;\nimport redis.clie"
},
{
"path": "src/main/java/cache/redis/provider/RCacheEntity.java",
"chars": 2320,
"preview": "package cache.redis.provider;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.apache.commons.lang3.StringUtils;\n"
},
{
"path": "src/main/java/config/GlobalConfig.java",
"chars": 836,
"preview": "package config;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.StringUtils;\n\nimport java.io.InputStr"
},
{
"path": "src/main/java/config/QingWeatherCityConfig.java",
"chars": 1663,
"preview": "package config;\n\nimport com.alibaba.fastjson.JSON;\nimport lombok.Getter;\nimport lombok.extern.slf4j.Slf4j;\nimport robot."
},
{
"path": "src/main/java/config/RedisConfig.java",
"chars": 1046,
"preview": "package config;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.StringUtils;\n\nimport java.io.InputStr"
},
{
"path": "src/main/java/cons/WxMsg.java",
"chars": 413,
"preview": "package cons;\n\n/**\n * Created by IntelliJ IDEA.\n *\n * @author Javior\n * @date 2019/6/19 18:39\n */\npublic class WxMsg {\n "
},
{
"path": "src/main/java/enums/CommandType.java",
"chars": 643,
"preview": "package enums;\n\nimport lombok.Getter;\n\n/**\n * Created by IntelliJ IDEA.\n *\n * @author Javior\n * @date 2019/6/20 15:38\n *"
},
{
"path": "src/main/java/enums/FriendType.java",
"chars": 261,
"preview": "package enums;\n\nimport lombok.Getter;\n\n/**\n * Created by IntelliJ IDEA.\n *\n * @author Javior\n * @date 2019/6/17 16:49\n *"
},
{
"path": "src/main/java/enums/GroupType.java",
"chars": 415,
"preview": "package enums;\n\n\nimport lombok.Getter;\n\n@Getter\npublic enum GroupType {\n /**\n * 默认级别\n */\n GROUP_DEFAULT,\n "
},
{
"path": "src/main/java/enums/RubbishType.java",
"chars": 1037,
"preview": "package enums;\n\nimport lombok.Getter;\n\n/**\n * Created by IntelliJ IDEA.\n *\n * @author Javior\n * @date 2019/7/1 21:42\n */"
},
{
"path": "src/main/java/main/WechatBotClient.java",
"chars": 4650,
"preview": "package main;\n\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\n\nimport config.GlobalConfig;\nimport cons"
},
{
"path": "src/main/java/main/facade/DealMessage.java",
"chars": 1422,
"preview": "package main.facade;\n\nimport IdentifyCommand.PreProcessMessage;\nimport cons.WxMsg;\nimport lombok.extern.slf4j.Slf4j;\nimp"
},
{
"path": "src/main/java/main/facade/DoCommand.java",
"chars": 603,
"preview": "package main.facade;\n\nimport IdentifyCommand.PreProcessMessage;\nimport lombok.extern.slf4j.Slf4j;\nimport main.service.gr"
},
{
"path": "src/main/java/main/service/everydayHelloMsg/EveryDayHelloWhiteList.java",
"chars": 3006,
"preview": "package main.service.everydayHelloMsg;\n\nimport config.GlobalConfig;\nimport lombok.Getter;\nimport lombok.extern.slf4j.Slf"
},
{
"path": "src/main/java/main/service/friendMsg/CheckFriendType.java",
"chars": 1866,
"preview": "package main.service.friendMsg;\n\nimport config.GlobalConfig;\nimport enums.FriendType;\nimport lombok.extern.slf4j.Slf4j;\n"
},
{
"path": "src/main/java/main/service/friendMsg/FriendChat.java",
"chars": 1272,
"preview": "package main.service.friendMsg;\n\nimport api.ChatApi;\nimport config.GlobalConfig;\nimport enums.FriendType;\nimport lombok."
},
{
"path": "src/main/java/main/service/groupMsg/CheckGroupType.java",
"chars": 3584,
"preview": "package main.service.groupMsg;\n\nimport config.GlobalConfig;\nimport enums.GroupType;\nimport lombok.extern.slf4j.Slf4j;\nim"
},
{
"path": "src/main/java/main/service/groupMsg/GroupChat.java",
"chars": 1261,
"preview": "package main.service.groupMsg;\n\nimport api.ChatApi;\nimport lombok.extern.slf4j.Slf4j;\nimport me.xuxiaoxiao.chatapi.wecha"
},
{
"path": "src/main/java/main/service/groupMsg/GroupTextCommand.java",
"chars": 4128,
"preview": "package main.service.groupMsg;\n\nimport IdentifyCommand.CheckCommandType;\nimport IdentifyCommand.PreProcessMessage;\nimpor"
},
{
"path": "src/main/java/robot/AToolBox/ToolBoxRubbish.java",
"chars": 6030,
"preview": "package robot.AToolBox;\n\nimport api.entity.RubbishToolBoxResponseEntity;\nimport cache.redis.RubbishLinkCacheFactory;\nimp"
},
{
"path": "src/main/java/robot/AToolBox/entity/ToolBoxRubbishContentEntity.java",
"chars": 238,
"preview": "package robot.AToolBox.entity;\n\nimport lombok.Data;\n\n/**\n * Created by IntelliJ IDEA.\n *\n * @author Javior\n * @date 2019"
},
{
"path": "src/main/java/robot/Ciba/CibaEveryDayHello.java",
"chars": 681,
"preview": "package robot.Ciba;\n\nimport com.alibaba.fastjson.JSON;\nimport config.GlobalConfig;\nimport robot.Ciba.entity.CibaEveryDay"
},
{
"path": "src/main/java/robot/Ciba/entity/CibaEveryDayHelloEntity.java",
"chars": 826,
"preview": "package robot.Ciba.entity;\n\nimport cons.WxMsg;\nimport lombok.Data;\n\nimport java.util.List;\n\n/**\n * Created by IntelliJ I"
},
{
"path": "src/main/java/robot/QingyunkeRobot/QingyunkeRobot.java",
"chars": 1395,
"preview": "package robot.QingyunkeRobot;\n\nimport config.GlobalConfig;\nimport org.apache.commons.lang3.StringUtils;\nimport robot.Qin"
},
{
"path": "src/main/java/robot/QingyunkeRobot/QingyunkeWeather/QingWeather.java",
"chars": 2338,
"preview": "package robot.QingyunkeRobot.QingyunkeWeather;\n\nimport config.GlobalConfig;\nimport org.apache.commons.lang3.StringUtils;"
},
{
"path": "src/main/java/robot/QingyunkeRobot/QingyunkeWeather/QingWeatherCityId.java",
"chars": 1548,
"preview": "package robot.QingyunkeRobot.QingyunkeWeather;\n\nimport config.QingWeatherCityConfig;\nimport robot.QingyunkeRobot.Qingyun"
},
{
"path": "src/main/java/robot/QingyunkeRobot/QingyunkeWeather/entity/QingWeatherCityEntity.java",
"chars": 243,
"preview": "package robot.QingyunkeRobot.QingyunkeWeather.entity;\n\nimport lombok.Data;\n\n@Data\npublic class QingWeatherCityEntity {\n "
},
{
"path": "src/main/java/robot/QingyunkeRobot/QingyunkeWeather/entity/QingWeatherEntity.java",
"chars": 2402,
"preview": "package robot.QingyunkeRobot.QingyunkeWeather.entity;\n\nimport cons.WxMsg;\nimport lombok.Data;\n\nimport java.util.List;\n\n\n"
},
{
"path": "src/main/java/robot/QingyunkeRobot/entity/QingyunkeResponseEntity.java",
"chars": 549,
"preview": "package robot.QingyunkeRobot.entity;\n\n\nimport org.apache.commons.lang3.StringUtils;\n\npublic class QingyunkeResponseEntit"
},
{
"path": "src/main/java/robot/RollToolsApi/RollNews.java",
"chars": 2811,
"preview": "package robot.RollToolsApi;\n\nimport cache.redis.NewsCacheFactory;\nimport cache.redis.entity.NewsCacheEntity;\nimport com."
},
{
"path": "src/main/java/robot/RollToolsApi/RollWeather.java",
"chars": 1234,
"preview": "package robot.RollToolsApi;\n\nimport config.GlobalConfig;\nimport org.apache.commons.lang3.StringUtils;\nimport robot.RollT"
},
{
"path": "src/main/java/robot/RollToolsApi/entity/RollNewsContentEntity.java",
"chars": 423,
"preview": "package robot.RollToolsApi.entity;\n\nimport lombok.Data;\n\nimport java.util.List;\n\n/**\n * Created by IntelliJ IDEA.\n *\n * "
},
{
"path": "src/main/java/robot/RollToolsApi/entity/RollNewsDetailsEntity.java",
"chars": 234,
"preview": "package robot.RollToolsApi.entity;\n\nimport lombok.Data;\n\n/**\n * Created by IntelliJ IDEA.\n *\n * @author Javior\n * @date "
},
{
"path": "src/main/java/robot/RollToolsApi/entity/RollNewsEntity.java",
"chars": 1493,
"preview": "package robot.RollToolsApi.entity;\n\nimport IdentifyCommand.PreProcessMessage;\nimport config.GlobalConfig;\nimport cons.Wx"
},
{
"path": "src/main/java/robot/RollToolsApi/entity/RollWeatherEntity.java",
"chars": 1113,
"preview": "package robot.RollToolsApi.entity;\n\nimport cons.WxMsg;\nimport lombok.Data;\n\n@Data\npublic class RollWeatherEntity {\n\n "
},
{
"path": "src/main/java/robot/RubbishClassificationApp/RubbishApp.java",
"chars": 1555,
"preview": "package robot.RubbishClassificationApp;\n\n\nimport config.GlobalConfig;\nimport enums.RubbishType;\nimport lombok.extern.slf"
},
{
"path": "src/main/java/robot/Zhihu/ZhihuHot.java",
"chars": 3272,
"preview": "package robot.Zhihu;\n\nimport IdentifyCommand.PreProcessMessage;\nimport cache.redis.ZhihuHotCacheFactory;\nimport cache.re"
},
{
"path": "src/main/java/robot/Zhihu/entity/ZhihuHotContentEntity.java",
"chars": 288,
"preview": "package robot.Zhihu.entity;\n\nimport lombok.Data;\n\n/**\n * Created by IntelliJ IDEA.\n *\n * @author Javior\n * @date 2019/7/"
},
{
"path": "src/main/java/robot/Zhihu/entity/ZhihuHotDetailEntity.java",
"chars": 555,
"preview": "package robot.Zhihu.entity;\n\nimport cons.WxMsg;\nimport lombok.Data;\n\n/**\n * Created by IntelliJ IDEA.\n *\n * @author Javi"
},
{
"path": "src/main/java/robot/Zhihu/entity/ZhihuHotEntity.java",
"chars": 868,
"preview": "package robot.Zhihu.entity;\n\nimport cons.WxMsg;\nimport lombok.Data;\n\nimport java.util.List;\n\n/**\n * Created by IntelliJ "
},
{
"path": "src/main/java/schedule/EverydayHelloSchedule.java",
"chars": 3078,
"preview": "package schedule;\n\nimport config.GlobalConfig;\nimport lombok.extern.slf4j.Slf4j;\n\nimport org.apache.commons.lang3.String"
},
{
"path": "src/main/java/schedule/base/BaseScheduleTask.java",
"chars": 1014,
"preview": "package schedule.base;\n\n\nimport org.apache.commons.lang3.time.StopWatch;\n\nimport lombok.AllArgsConstructor;\nimport lombo"
},
{
"path": "src/main/java/schedule/task/FriendEverydayTask.java",
"chars": 1006,
"preview": "package schedule.task;\n\nimport org.apache.commons.lang3.StringUtils;\n\nimport api.EveryDayHelloApi;\nimport lombok.extern."
},
{
"path": "src/main/java/schedule/task/GroupEverydayTask.java",
"chars": 993,
"preview": "package schedule.task;\n\n\nimport org.apache.commons.lang3.StringUtils;\n\nimport api.EveryDayHelloApi;\nimport lombok.extern"
},
{
"path": "src/main/java/utils/AtMeMsg.java",
"chars": 1668,
"preview": "package utils;\n\nimport cons.WxMsg;\nimport me.xuxiaoxiao.chatapi.wechat.entity.contact.WXGroup;\nimport me.xuxiaoxiao.chat"
},
{
"path": "src/main/java/utils/DateUtil.java",
"chars": 2107,
"preview": "package utils;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\n/**\n * Created by IntelliJ IDEA.\n *\n * @autho"
},
{
"path": "src/main/java/utils/GroupMsgUtil.java",
"chars": 567,
"preview": "package utils;\n\nimport me.xuxiaoxiao.chatapi.wechat.entity.message.WXMessage;\nimport org.apache.commons.lang3.StringUtil"
},
{
"path": "src/main/java/utils/HttpRequestUtil.java",
"chars": 1673,
"preview": "package utils;\n\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.lang3.StringUtils;\n\nimport java.io.Buffered"
},
{
"path": "src/main/java/utils/QRCodeUtil.java",
"chars": 277,
"preview": "package utils;\n\n/**\n * Created by IntelliJ IDEA.\n *\n * @author Javior\n * @date 2019/6/29 17:57\n */\npublic class QRCodeUt"
},
{
"path": "src/main/java/utils/ScheduleUtil.java",
"chars": 1237,
"preview": "package utils;\n\nimport java.util.concurrent.TimeUnit;\n\nimport lombok.NonNull;\nimport lombok.extern.slf4j.Slf4j;\nimport s"
},
{
"path": "src/main/java/utils/ThreadPoolUtil.java",
"chars": 1344,
"preview": "package utils;\n\nimport lombok.extern.slf4j.Slf4j;\n\nimport java.util.concurrent.*;\n\n/**\n * Created by IntelliJ IDEA.\n *\n "
},
{
"path": "src/main/resources/city.json",
"chars": 282424,
"preview": "[\n {\n \"_id\": 1,\n \"id\": 1,\n \"pid\": 0,\n \"city_code\": \"101010100\",\n \"city_name\": \"北京\"\n },\n {\n \"_id\": 2"
},
{
"path": "src/main/resources/config.properties",
"chars": 2757,
"preview": "# 所有回复的消息前缀\nreplyPrefix=\n\n##############################\n\n# 指令前缀,留空为默认值。默认为两个问号(中英皆可)\ncommandPrefix=\n\n##################"
},
{
"path": "src/main/resources/redis.properties",
"chars": 185,
"preview": "\n# 是否启用redis缓存。true为启用;false为禁用\nredis.enable=true\n\n########################\n## Redis配置。最好使用自己的,这个Redis搭在我的阿里云学生机上,不保证一直可"
},
{
"path": "src/test/java/CacheTest.java",
"chars": 4868,
"preview": "import api.RubbishApi;\nimport cache.redis.RubbishLinkCacheFactory;\nimport cache.redis.RubbishTypeCacheFactory;\nimport ca"
},
{
"path": "src/test/java/HttpTest.java",
"chars": 977,
"preview": "import api.NewsApi;\nimport api.RubbishApi;\nimport robot.RollToolsApi.RollNews;\nimport robot.Zhihu.ZhihuHot;\n\nimport java"
},
{
"path": "src/test/java/city.json",
"chars": 282424,
"preview": "[\n {\n \"_id\": 1,\n \"id\": 1,\n \"pid\": 0,\n \"city_code\": \"101010100\",\n \"city_name\": \"北京\"\n },\n {\n \"_id\": 2"
}
]
About this extraction
This page contains the full source code of the scorego/WechatRobot GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 84 files (683.9 KB), approximately 272.5k tokens, and a symbol index with 267 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.