springboot项目实现微信公众号推送天气
参考过B站一位博主使用前端实现微信公众号推送天气。
视频链接:https://www.bilibili.com/video/BV19P4y1Z7ix/?spm_id_from=333.1007.top_right_bar_window_default_collection.content.click&vd_source=a48f650eb4618ad7b619af295e1d833c
1.效果展示
2.代码展示
2.1 使用到的技术
SpringBoot、微信公众号相关api、Spring定时任务等
2.2 前置准备
2.2.1 引入依赖
<?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>com.atguigu</groupId>
<artifactId>forecast</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.6.RELEASE</version>
</parent>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--web启动类-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--方便请求微信服务器-->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>4.1.0</version>
</dependency>
<!--方便操作json数据-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.21</version>
</dependency>
<!--简化实体类-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--让map存的值有过期时间-->
<dependency>
<groupId>net.jodah</groupId>
<artifactId>expiringmap</artifactId>
<version>0.5.8</version>
</dependency>
<!-- 发送http请求 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
</dependencies>
<-- 有了它就能打包运行 -->
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.2.2 写配置文件
application.yml:
server:
port: 8888
wechat:
mpAppId: wx546513321345bed #公众号获取
mpAppSecret: 646513213wdwadasdasfsas #公众号获取
touser: adasd654165465464131141 #当有人关注公众号时就可以看到
templateId: 35dfsa65f4as5f1a321f3a4f4f6f #模板消息id
注意:这些信息需要到微信公众号官方文档获取,由于个人测试使用,所以需要申请测试号
1.首先申请测试号。
申请地址:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
申请好之后,会在主页面看到appid和appSecret,如图所示:
2.然后扫描自己的测试号,就会得到扫描过的微信号的touser信息,如图所示:
3.继续往下翻就会看到测试模板信息,添加完测试模板后会得到template_id,模板内容就是我们后续要推送到公众号的内容,需要注意模板内容需要用{{key.DATA}}的形式,key需要自己指定如图所示:
2.2.3 写工具类和配置类
/**
* 取配置文件中以wechat为前缀,以指定字段名为后缀的数据
*/
@Data
@Component
@ConfigurationProperties(prefix = "wechat")
public class WechatAccountConfig {
private String mpAppId;
private String mpAppSecret;
private String touser;
private String templateId;
}
/**
* java中的第三方调用微信公众号接口的api配置,非常方便
*/
@Component
public class WeChatMpConfig {
@Autowired
private WechatAccountConfig wechatAccountConfig;
@Bean
public WxMpService wxMpService(){
WxMpService wxMpService = new WxMpServiceImpl();
wxMpService.setWxMpConfigStorage(wxMpConfigStorage());
return wxMpService;
}
@Bean
public WxMpConfigStorage wxMpConfigStorage(){
WxMpDefaultConfigImpl wxMpConfigStorage = new WxMpDefaultConfigImpl();
wxMpConfigStorage.setAppId(wechatAccountConfig.getMpAppId());
wxMpConfigStorage.setSecret(wechatAccountConfig.getMpAppSecret());
return wxMpConfigStorage;
}
}
/**
* 用来发http请求的,请求第三方天气接口以及情话接口
*/
public class HttpClient {
public static String doGet(String url) {
CloseableHttpClient httpClient = null;
CloseableHttpResponse response = null;
String result = "";
try {
// 通过址默认配置创建一个httpClient实例
httpClient = HttpClients.createDefault();
// 创建httpGet远程连接实例
HttpGet httpGet = new HttpGet(url);
// 设置请求头信息,鉴权
// httpGet.setHeader("Authorization", "Bearer da3efcbf-0845-4fe3-8aba-ee040be542c0");
// 设置配置请求参数
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(35000)// 连接主机服务超时时间
.setConnectionRequestTimeout(35000)// 请求超时时间
.setSocketTimeout(60000)// 数据读取超时时间
.build();
// 为httpGet实例设置配置
httpGet.setConfig(requestConfig);
// 执行get请求得到返回对象
response = httpClient.execute(httpGet);
// 通过返回对象获取返回数据
HttpEntity entity = response.getEntity();
// 通过EntityUtils中的toString方法将结果转换为字符串
result = EntityUtils.toString(entity);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
if (null != response) {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != httpClient) {
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
public static String doPost(String url, Map<String, Object> paramMap) {
CloseableHttpClient httpClient = null;
CloseableHttpResponse httpResponse = null;
String result = "";
// 创建httpClient实例
httpClient = HttpClients.createDefault();
// 创建httpPost远程连接实例
HttpPost httpPost = new HttpPost(url);
// 配置请求参数实例
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(35000)// 设置连接主机服务超时时间
.setConnectionRequestTimeout(35000)// 设置连接请求超时时间
.setSocketTimeout(60000)// 设置读取数据连接超时时间
.build();
// 为httpPost实例设置配置
httpPost.setConfig(requestConfig);
// 设置请求头
httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
// 封装post请求参数
if (null != paramMap && paramMap.size() > 0) {
List<NameValuePair> nvps = new ArrayList<>();
// 通过map集成entrySet方法获取entity
Set<Map.Entry<String, Object>> entrySet = paramMap.entrySet();
// 循环遍历,获取迭代器
Iterator<Map.Entry<String, Object>> iterator = entrySet.iterator();
while (iterator.hasNext()) {
Map.Entry<String, Object> mapEntry = iterator.next();
nvps.add(new BasicNameValuePair(mapEntry.getKey(), mapEntry.getValue().toString()));
}
// 为httpPost设置封装好的请求参数
try {
httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
try {
// httpClient对象执行post请求,并返回响应参数对象
httpResponse = httpClient.execute(httpPost);
// 从响应对象中获取响应内容
HttpEntity entity = httpResponse.getEntity();
result = EntityUtils.toString(entity);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
if (null != httpResponse) {
try {
httpResponse.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != httpClient) {
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
}
/**
* 用来计算日期的,每定时任务每成功推送消息到微信公众号一次,loveDate就会调用add()方法加1
*/
public class WxUtil {
public static Integer loveDate=717;
public static void add(){
loveDate++;
}
}
2.2.4 写程序入口
@SpringBootApplication
public class ServiceForecastApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceForecastApplication.class);
}
}
2.3 实现业务代码
2.3.1 写service接口以及实现类
接口:
public interface MessageService {
;
/**
* 发送模板消息推送到公众号接口
* @param loveDate
*/
void sendMessage(Integer loveDate);
}
实现类:
@Service
public class MessageServiceImpl implements MessageService {
@Autowired
private WxMpService wxMpService;
@Autowired
private WechatAccountConfig wechatAccountConfig;
@Override
public void sendMessage(Integer loveDate) {
WxMpTemplateMessage.WxMpTemplateMessageBuilder builder = WxMpTemplateMessage.builder();
//指定具体的已关注过测试号的用户
builder.toUser(wechatAccountConfig.getTouser());
builder.templateId(wechatAccountConfig.getTemplateId());
WxMpTemplateMessage build = builder.build();
//封装日期 年 月 日 周
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("今天是yyyy年MM月dd日 EEEE");
String nowDate = simpleDateFormat.format(new Date());
//封装天气信息
JSONObject jsonObject= getWeather();
//获取土味情话
String loveTalk= getLoveTalk();
//String loveTalk="我生在南方,活在南方,栽在你手里,总算是去过不一样的地方。";
String s1="";
String s2="";
//字数大于20,推送到公众号展示的时候会被截断,因此把长文本内容分为两段
if (loveTalk.length()>20){
s1 = loveTalk.substring(0, 20);
s2 = loveTalk.substring(20);
}else{
s1=loveTalk;
}
//封装消息模板
build.addData(new WxMpTemplateData("nowDate",nowDate))
.addData(new WxMpTemplateData("city","洛阳"))
.addData(new WxMpTemplateData("wea",jsonObject.getString("wea")))
.addData(new WxMpTemplateData("low",jsonObject.getString("tem_night")))
.addData(new WxMpTemplateData("high",jsonObject.getString("tem_day")))
.addData(new WxMpTemplateData("tem",jsonObject.getString("tem")))
.addData(new WxMpTemplateData("win",jsonObject.getString("win")))
.addData(new WxMpTemplateData("win_speed",jsonObject.getString("win_speed")))
.addData(new WxMpTemplateData("win_meter",jsonObject.getString("win_meter")))
.addData(new WxMpTemplateData("air",jsonObject.getString("air")))
.addData(new WxMpTemplateData("humidity",jsonObject.getString("humidity")))
.addData(new WxMpTemplateData("loveDATE",String.valueOf(loveDate)))
.addData(new WxMpTemplateData("txt",s1))
.addData(new WxMpTemplateData("txt1",s2));
String msg = null;
try {
//发送消息模板
msg = wxMpService.getTemplateMsgService().sendTemplateMsg(build);
WxUtil.add();
System.out.println(msg);
} catch (WxErrorException e) {
e.printStackTrace();
}
}
//请求土味情话接口
private String getLoveTalk() {
String resultString = HttpClient.doGet("https://apis.tianapi.com/saylove/index?key=959e944b86a97c4baf0e4a7762488751");
JSONObject jsonObject = JSONObject.parseObject(resultString);
String result = jsonObject.getString("result");
return JSONObject.parseObject(result).getString("content");
}
//请求天气接口,获取天气信息
private JSONObject getWeather() {
String resultString = HttpClient.doGet("http://v1.yiketianqi.com/free/day?appid=36143179&appsecret=3ttN9WsN&unescape=1&cityid=" + 101180901);
JSONObject jsonObject = JSONObject.parseObject(resultString);
return jsonObject;
}
}
请求天气接口地址:https://www.tianqiapi.com/index/doc?version=day
请求情话接口地址:https://www.tianapi.com/apiview/80
2.3.2 写定时任务
@Configuration //1.标记配置类
@EnableScheduling //2.开启定时任务
public class StaticScheduleTask {
@Autowired
private MessageService messageService;
/**
* 我这里为了测试,每五秒钟执行一次,
* 投入使用的时候,比如可以设置成每天6点,
* 这样每天执行一次,前面设置过的loveDate就会加1
* 就能够计算好日期
* cron表达式在网上能搜到
*/
//3.添加定时任务
@Scheduled(cron = "0/5 * * * * *")
public void Scheduled(){
messageService.sendMessage(WxUtil.loveDate);
}
}
2.4 打包部署到服务器
2.4.1 执行maven package命令打成jar包,在target目录中可以找到,如图所示:
2.4.2 上传到服务器并运行
首先需要购买一台服务器,比如阿里云腾讯云等,否则就必须保证自己电脑一直运行着此程序,或者在GitHub运行也行,网上应该有相关教程。
购买之后,使用XShell或者FinalShell等远程连接工具连接上自己的云服务器,上传jar包(需要有JDK环境),输入命令运行
前台运行:java -jar forecast.jar
后台运行:nohup java -jar forecast.jar &