springboot项目实现微信公众号推送天气

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 &

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值