一、资料链接

1、github地址

https://github.com/qq1534774766/wx-push

2、教程地址

https://blog.csdn.net/qq15347747/article/details/126521774

3、易客云API(自动发送天气)

https://yikeapi.com/account/index

4、apispace-各种接口(名人名言)

https://www.apispace.com/console/api?orgId=6356

5、微信公众平台

https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index

二、准备工作

(一)进入接口测试页面

1、找到微信公众平台

2、进入开发者工具

3、进入公众平台测试帐号

4、拉到最下面

微信扫码关注

5、记录下述信息

(二)获取天气预报接口地址

1、进入易客云API(自动发送天气)

https://yikeapi.com/account/index

2、注册登录

3、复制参数appid和appsecret的值

4、记录下述信息

(三)获取(名言警句)地址

1、进入apispace-各种接口

https://www.apispace.com/console/api?orgId=6356

2、注册登录

3、购买名言警句

4、进入我的api,点击测试

5、复制token地址

6、记录下述信息

三、开发部署

1、下载项目

git下载:https://github.com/qq1534774766/wx-push.git

2、填写上述参数(application.yml)

3、配置定时

填写cron表达式@Scheduled(cron = "0 30 7 ? * *")

实现方式:import org.springframework.scheduling.annotation.Scheduled;

4、启动项目

5、测试

修改天气预报城市:localhost:8081

测试发送消息:localhost:8081/send

6、打包上传服务器

nohup java -jar wx.jar >wx.txt &

sudo nohup /home/bigdata/tools/jdk1.8.0_291/bin/java -jar wx-push-0.0.1-SNAPSHOT.jar > nohup_wx_push.log &

问题1:nohup: 无法运行命令“java“: 没有那个文件或目录

解决1:java绝对路径

问题2:unable to run tomcat server

解决2:修改端口大于1000,小于1000的端口需要root用户启动或设置

四、优化

(一)cron表达式配置及含义

1、启动类加注解

@EnableScheduling

2、几分钟执行一次

/**
* 固定频率执行。fixedDelay的单位是ms
*/
@Scheduled(fixedDelay = 1000)
public void remindTask2() throws InterruptedException {
log.info("每隔1s执行一次 当前线程名称{} 当前执行次数{}", Thread.currentThread().getName(), task1Number.incrementAndGet());
}

3、cron表达式配置

5秒执行一次

 @Scheduled(cron = "*/5 * * * * ? ")
public void remindTask() throws InterruptedException {
log.info("每隔5秒执行一次, 当前线程名称{} 当前执行次数{}", Thread.currentThread().getName(), taskNumber.incrementAndGet());
}

ps:?的含义是

“?”字符仅被用于天(月)和天(星期)两个子表达式,表示不指定值 当2个子表达式其中之一被指定了值以后,为了避免冲突,需要将另一个子表达式的值设为“?”

项目使用

@Scheduled(cron = "0 30 7 ? * *")
@RequestMapping("/send")
public String send() {
try {
return sendService.sendWeChatMsg();
} catch (Exception e) {
e.printStackTrace();
}
JSONObject json = new JSONObject();
json.put("msg", "信息推送失败");
return json.toJSONString();
}

corn从左到右(用空格隔开):秒 分 小时 月份中的日期 月份 星期中的日期 年份

DayofMonth和DayofWeek会相互影响

校验:https://www.bejson.com/othertools/cronvalidate/

日期和星期相互影响,必须配置一个?【?表示不指定周几或每月几号,因为二者相互影响】

配置哪个含义相同

(二)配置名言外的其他api(apispace)

找到名言警句的配置地址

配置其他api

1、示例文档地址

https://www.apispace.com/console/api?orgId=6356

2、示例代码

OkHttpClient client = new OkHttpClient().newBuilder().build();
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody body = RequestBody.create(mediaType, "titleID=1");
Request request = new Request.Builder()
.url("https://eolink.o.apispace.com/myjj/common/aphorism/getAphorismList")
.method("POST",body)
.addHeader("X-APISpace-Token","s2qvfzkmuzb9vq7pvw8tnll882rhrarl")
.addHeader("Authorization-Type","apikey")
.addHeader("Content-Type","application/x-www-form-urlencoded")
.build(); Response response = client.newCall(request).execute();

3、实际代码

ProverbServiceImpl

    @Override
public String getOneNormalProverb() {
String proverb = null;
try {
OkHttpClient client = new OkHttpClient().newBuilder().build();
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody body = RequestBody.create(mediaType, "titleID="+new Random().nextInt(9));
Request request = new Request.Builder()
.url("https://eolink.o.apispace.com/myjj/common/aphorism/getAphorismList")
.method("POST", body)
.addHeader("X-APISpace-Token", configConstant.getToken())
.addHeader("Authorization-Type", "apikey")
.addHeader("Content-Type", "")
.build();
        Response response = client.newCall(request).execute();
JSONObject jsonObject = JSONObject.parseObject(response.body().string());
//取出全部句子
JSONArray allProverb = JSONObject.parseArray((String) jsonObject.getJSONArray("result").getJSONObject(0).get("words"));
//随机取出一条句子
String s = (String) allProverb.get(new Random().nextInt(allProverb.size()));
//去除无关元素
proverb = s.replaceAll("^.*、", "");
} catch (IOException e) {
throw new RuntimeException(e);
}
return proverb;
}

通过有道翻译为英文

 @Override
public String translateToEnglish(String sentence) {
String result = null;
try {
OkHttpClient client = new OkHttpClient().newBuilder().build();
Request request = new Request.Builder()
.url("https://fanyi.youdao.com/translate?&doctype=json&type=AUTO&i="+sentence)
.get()
.addHeader("Content-Type","")
.build();
Response response = client.newCall(request).execute();
result = response.body().string();
//解析
JSONObject jsonObject = JSONObject.parseObject(result);
result = jsonObject.getJSONArray("translateResult").getJSONArray(0).getJSONObject(0).getString("tgt");
}catch (Exception e) {
e.printStackTrace();
}
return result;
}

(三)配置天气预报的原理(易客云)

1、得到当日天气

public JSONObject getWeatherByCity() {
String result = null;
try {
OkHttpClient client = new OkHttpClient.Builder().build();
HttpUrl url = new HttpUrl.Builder()
.scheme("https")
.host("www.yiketianqi.com")
.addPathSegments("free/day")
.addQueryParameter("appid", configConstant.getWeatherAppId())
.addQueryParameter("appsecret", configConstant.getWeatherAppSecret())
.addQueryParameter("city", configConstant.getCity())
.addQueryParameter("unescape", "1")
.build();
Request request = new Request.Builder()
.url(url)
.get()
.build();
Response re = client.newCall(request).execute();
result = re.body().string();
} catch (IOException e) {
e.printStackTrace();
}
return JSONObject.parseObject(result);
}

2、得到三日天气

public Map<String, String> getTheNextThreeDaysWeather() {
Map<String, String> map = null;
try {
OkHttpClient client = new OkHttpClient.Builder().build();
HttpUrl url = new HttpUrl.Builder()
.scheme("https")
.host("yiketianqi.com")
.addPathSegments("free/week")
.addQueryParameter("appid", configConstant.getWeatherAppId())
.addQueryParameter("appsecret", configConstant.getWeatherAppSecret())
.addQueryParameter("city", configConstant.getCity())
.build();
Request request = new Request.Builder()
.url(url)
.get()
.build();
Response response = client.newCall(request).execute();
String responseResult = response.body().string();
if (!StringUtils.hasText(responseResult)) {
logger.error("获取三天天气失败,检查配置文件");
throw new RuntimeException("获取三天天气失败,检查配置文件");
}
logger.info(responseResult);
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
LocalDate now = LocalDate.now(zoneId);
//封装今天,明天,后天的时间
/**
* 原因分析:从天气api获取到未来的天气的日期是 01 02 03 的两位数。
* 而Java中的LocalDate的日期,是一位数的 1 2 3 。
* 因为一开始用是String类型比较,所以01≠1,最后导致异常。
*/
Map<Integer, String> daySet = new HashMap<>();
daySet.put(now.getDayOfMonth(), "今"); // 用now,就不会报错了,1 2 3
daySet.put(now.plusDays(1L).getDayOfMonth(), "明");
daySet.put(now.plusDays(2L).getDayOfMonth(), "后");
//过滤,提取结果
JSONObject jsonObject = JSONObject.parseObject(responseResult);
if (jsonObject.containsKey("errmsg")) {
logger.error(jsonObject.getString("errmsg"));
throw new IllegalArgumentException(jsonObject.getString("errmsg"));
}
map = jsonObject.getJSONArray("data").stream()
.peek(o -> {
String date = getStringFromJson(o, "date").substring(8);
((JSONObject) o).put("date", date);
})
.filter(o -> daySet.containsKey(getIntegerFromJson(o, "date")))
.collect(Collectors.toMap(
key -> daySet.get(getIntegerFromJson(key, "date")),
value -> getStringFromJson(value, "wea")));
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("获取失败");
}
return map;
}

(四)发送消息

1、封装各项请求的内容

if (configConstant.isEnableDaily() && StringUtils.hasText(configConstant.getToken())) {
//名言警句,中文
String noteZh = null;
try {
noteZh = proverbService.getOneNormalProverb();
JSONObject note_Zh = JsonObjectUtil.packJsonObject(noteZh, "#879191");
resultMap.put("note_Zh", note_Zh);
logger.info("note_Zh:{}", note_Zh);
} catch (Exception e) {
logger.info("名言警句获取失败,检查ApiSpace的token是否正确?套餐是否过期?");
}
//名言警句,英文
try {
JSONObject note_En = JsonObjectUtil.packJsonObject(proverbService.translateToEnglish(noteZh), "#879191");
resultMap.put("note_En", note_En);
logger.info("note_En:{}", note_En);
} catch (Exception e) {
logger.info("名言警句翻译失败,网易云翻译接口无法使用");
}
}
//封装数据并发送
sendMessage(accessToken, errorList, resultMap, opedId);

2、发送到微信token

   private void sendMessage(String accessToken, List<JSONObject> errorList, HashMap<String, Object> resultMap, String opedId) {
JSONObject templateMsg = new JSONObject(new LinkedHashMap<>());
templateMsg.put("touser", opedId);
templateMsg.put("template_id", configConstant.getTemplateId());
templateMsg.put("data", new JSONObject(resultMap));
String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken; String sendPost = HttpUtil.sendPost(url, templateMsg.toJSONString());
JSONObject WeChatMsgResult = JSONObject.parseObject(sendPost);
if (!"0".equals(WeChatMsgResult.getString("errcode"))) {
JSONObject error = new JSONObject();
error.put("openid", opedId);
error.put("errorMessage", WeChatMsgResult.getString("errmsg"));
errorList.add(error);
}
}

五、技术总结

1、Scheduleh注解定时调任务

2、微信token发送指定消息

3、调用接口得到数据(天气预报和各种api)

4、姓名如何在方法头上标注

5、代码结构

6、配置参数调用-通过value和自动注入

configConstant.getWeatherAppId()

【小项目】微信定时推送天气预报Github项目使用及原理介绍-包含cron、天气预报、常用api的更多相关文章

  1. Git-最简单的本地项目变成版本仓库,然后把内容推送到GitHub仓库

    (注:本文的前提是本地Git仓库和github仓库之间已经存在SSH key了,所以如果没有建立联系的小伙伴们请先建立联系) 具体操作: 一:把本地项目变成版本仓库 1.把本地的一个项目目录编程版本库 ...

  2. 微信公众号 模板消息 定时推送 java

    前提:业务需要,要做一个关于月报的微信消息推送.即每个月定时自动发送一条消息 给关注 公众号的人 用的是 公众号的测试账号(实际开发需要认证的公众号) 微信官网的 模板消息接口规则: 1.所有服务号都 ...

  3. 如何将git本地创建的项目推送到github仓库

    除了集中式的版本控制系统CVS和SVN外,还有目前世界上最先进的分布式版本控制系统Git,它的创始人是创建了linux的大神 - linus.GitHub网站与2008年开始服役,为开源项目免费提供G ...

  4. 将本地的项目推送到github上

    好像还是不能用git在本地直接建一个repository,然后推送到github,这是把本地项目推送到github上已经建好的裤 …or create a new repository on the ...

  5. Eclipse项目推送至github

    0. 安装好git,配置正确 网上教程很多,略 1. 将eclipse中的项目放入git本地库 1.右键项目-->Team-->Share Project 2.勾选 Use or crea ...

  6. Git将一个项目同时从本地推送到GitHub和Gitee

    前言 博主是根据自己的情况写这篇博文的,每个人遇到的情况和需求可能不一样哈,所以初始的步骤也不一定一致,但是同时推送到Github和Gitee的步骤都会是一致滴! Gitee拉取Github仓库 直接 ...

  7. 如何将本地项目推送到Github

    如何将本地项目推送到Github Tip:在本地要安装好Git,官网:https://git-scm.com/ 一个学习Git的好地方:https://try.github.io/ 在线闯关实战,边练 ...

  8. 两种github action 打包.Net Core 项目docker镜像推送到阿里云镜像仓库

    两种github action 打包.Net Core 项目docker镜像推送到阿里云镜像仓库 1.GitHub Actions 是什么? 大家知道,持续集成由很多操作组成,比如抓取代码.运行测试. ...

  9. 如何将本地的项目推送到github

    一.创建密钥 1.本地终端命令行生成密钥 访问密钥创建的帮助文档:https://help.github.com/en/github/authenticating-to-github/generati ...

  10. python 全栈开发,Day103(微信消息推送,结算中心业务流程)

    昨日内容回顾 第一部分:考试题(Python基础) 第二部分:路飞相关 1. 是否遇到bug?难解决的技术点?印象深刻的事? - orm操作费劲 - 最开始学习路由系统时候,匹配规则: 答案一: 有, ...

随机推荐

  1. 怎样编写正确、高效的 Dockerfile

    基础镜像 FROM 基础镜像 基础镜像的选择非常关键: 如果关注的是镜像的安全和大小,那么一般会选择 Alpine: 如果关注的是应用的运行稳定性,那么可能会选择 Ubuntu.Debian.Cent ...

  2. MySql的InnoDB的三层B+树可以存储两千万左右条数据的计算逻辑

    总结/朱季谦 B+树是一种在非叶子节点存放排序好的索引而在叶子节点存放数据的数据结构,值得注意的是,在叶子节点中,存储的并非只是一行表数据,而是以页为单位存储,一个页可以包含多行表记录.非叶子节点存放 ...

  3. Python抖音视频去水印,并打包成exe可执行文件

    前言 抖音里面的视频保存之后,会发现全都带有水印,所以如何解决视频去除水印就很有必要,所以教程来了,本次教程不仅会教大家如何去除视频里的水印,并且教大家将程序制作成exe可执行文件,可以发给你的好友使 ...

  4. aws-cli命令-vpcs及subnets相关的查询

    关于AWS上vpcs及subnets相关的查询,常用的命令如下: # 查询所有的vpc信息 aws ec2 describe-vpcs --output json # 查询所有所有的subnet相关的 ...

  5. StampedLock:一个并发编程中非常重要的票据锁

    摘要:一起来聊聊这个在高并发环境下比ReadWriteLock更快的锁--StampedLock. 本文分享自华为云社区<[高并发]一文彻底理解并发编程中非常重要的票据锁--StampedLoc ...

  6. 【NOI2016】 循环之美 题解

    Solution 由数论基础知识 答案即为$$\sum_{i = 1}^n\sum_{j = 1}^m[i \perp j][j \perp k]$$ 莫反套路可化为$$\sum_{d = 1}\mu ...

  7. 聊一聊被 .NET程序员 遗忘的 COM 组件

    一:背景 1.讲故事 最近遇到了好几起和 COM 相关的Dump,由于对 COM 整体运作不是很了解,所以分析此类dump还是比较头疼的,比如下面这个经典的 COM 调用栈. 0:044> ~~ ...

  8. 《吐血整理》高级系列教程-吃透Fiddler抓包教程(29)-Fiddler如何抓取Android7.0以上的Https包-终篇

    1.简介 上一篇宏哥介绍的Xposed是一款可以在不修改APK的情况下影响程序运行的框架.可以编写并加载自己编写的插件app,实现对目标apk的注入.拦截等.一般研究移动安全的都会使用Xposed. ...

  9. Unity破窗游戏制作(简易版)

    Unity破窗游戏制作(简易版) 参考:"对不起,我选择摸鱼"-<扫雷>小游戏开发实战,算法.源代码,基于Unity3D开发 - 掘金 (juejin.cn) 到&qu ...

  10. 分享个好东西两行前端代码搞定bilibili链接转视频!

    只需要在您的要解析B站视频的页面的</body>前面加上下面两行代码即可,脚本会在客户端浏览器里解析container所匹配到的容器里的B站超链接 (如果不是外围有a标签的超链接只是纯粹的 ...