• Java 微信公众号每日自动给女朋友推送问候


            近期网上又出现一股给女朋友做微信公众号推送的潮流,那么别人有的我女朋友也得有不是O.o 简单研究了一下做微信公众号推送的原理,简单来说就是后台服务器做个定时任务,然后定时调用微信公众平台提供的Web API接口(HTTP),发送模板消息(JSON数据)即可。技术栈及开发流程总结如下:

    • 前端:微信公众号-订阅号-测试号
    • 后端:SpringBoot + RestTemplate

     1.配置微信公众平台测试号

            点击打开微信公众平台链接( 微信公众平台 ),注册申请微信公众测试号。测试号可以体验微信公众平台所有的功能API接口,我们这里主要使用的是模板消息推送API。但测试号的局限性是只能使用默认的公众号名称且功能随时可能被下架有条件的可以申请企业订阅号/服务号(个人认证的订阅号不具有模板消息推送API权限,只有企业可以认证服务号)。测试号配置中比较重要的是以下几部分(参考开发文档 模板消息 | 微信开放文档 (qq.com)):

    • 测试号信息:包括appID和appsecret,用于获取Token与API接口进行身份校验

    • 用户列表:用于获取订阅用户的openId,推送到目标用户(必须先关注此订阅号)

    • 模板消息接口:用于配置推送的消息模板,包括模板ID(用于接口调用)、模板内容等。模板内容可设置参数(模板标题不可),供接口调用时使用,参数需以 {{params.DATA}} 格式配置。其中params是后端服务器传输过来的对应的JSON数据变量名称,DATA是前端模板消息的固定语法。

      

    1. //JSON数据传输格式示例
    2. {
    3. "touser":"OPENID",
    4. "template_id":"ngqIpbwh8bUfcSsECmogfXcV14J0tQlEpBO27izEYtY",
    5. "topcolor":"#FF0000",
    6. "data":{
    7. "date": {
    8. "value":"2022-09-04 星期日",
    9. "color":"#173177"
    10. },
    11. "remark":{
    12. "value":"♥",
    13. "color":"#173177"
    14. },
    15. "city": {
    16. "value":"北京",
    17. "color":"#173177"
    18. },
    19. "weather": {
    20. "value":"多云转晴",
    21. "color":"#173177"
    22. },
    23. ...
    24. }
    25. }

    2.数据接口封装

            在消息推送模板中,我们需要用到的数据包括气候(天气、温度、城市等)、恋爱天数、生日倒计时天数、彩虹屁语句这几部分,数据的获取方式如下:

    2.1  天行数据接口封装

            天行接口数据的获取也是通过Web API 发送请求的方式在response中来获取数据(RestTemplate),接口文档如下:

    1. public class DataUtils {
    2. /**
    3. * 获取 Weather 信息
    4. * @param restTemplate
    5. * @return
    6. */
    7. public static Weather getWeather(RestTemplate restTemplate){
    8. String responseJson = restTemplate.getForObject(WeChatConfigure.Weather_API, String.class);
    9. JSONObject responseResult = JSONObject.parseObject(responseJson);
    10. JSONObject jsonObject = responseResult.getJSONArray("newslist").getJSONObject(0);
    11. return jsonObject.toJavaObject(Weather.class);
    12. }
    13. /**
    14. * 获取 RainbowPi 信息
    15. * @param restTemplate
    16. * @return
    17. */
    18. public static String getRainbow(RestTemplate restTemplate){
    19. String responseJson = restTemplate.getForObject(WeChatConfigure.Rainbow_API, String.class);
    20. JSONObject responseResult = JSONObject.parseObject(responseJson);
    21. JSONObject jsonObject = responseResult.getJSONArray("newslist").getJSONObject(0);
    22. return jsonObject.getString("content");
    23. }
    24. }

     2.2 日期计算工具封装

            计算生日倒计时和计算恋爱天数的逻辑不同。计算生日倒计时需要判断生日日期是否已过,而计算恋爱天数相对简单,直接统计时间即可。

    1. public class DataUtils {
    2. /**
    3. * 计算生日天数 days
    4. * @return
    5. */
    6. public static int getBirthDays(String birthday) {
    7. SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    8. Calendar cToday = Calendar.getInstance(); // 存今天
    9. Calendar cBirth = Calendar.getInstance(); // 存生日
    10. int days = 0;
    11. try {
    12. cBirth.setTime(dateFormat.parse(birthday)); // 设置生日
    13. cBirth.set(Calendar.YEAR, cToday.get(Calendar.YEAR)); // 修改为本年
    14. if (cBirth.get(Calendar.DAY_OF_YEAR) < cToday.get(Calendar.DAY_OF_YEAR)) {
    15. // 生日已经过了,要算明年的了
    16. days = (cToday.getActualMaximum(Calendar.DAY_OF_YEAR) - cToday.get(Calendar.DAY_OF_YEAR)) + cBirth.get(Calendar.DAY_OF_YEAR);
    17. } else {
    18. // 生日还没过
    19. days = cBirth.get(Calendar.DAY_OF_YEAR) - cToday.get(Calendar.DAY_OF_YEAR);
    20. }
    21. } catch (ParseException e) {
    22. e.printStackTrace();
    23. }
    24. return days;
    25. }
    26. /**
    27. * 计算恋爱天数 days
    28. * @return
    29. */
    30. public static int getLoveDays(String loveday){
    31. SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    32. int days = 0;
    33. try {
    34. long time = System.currentTimeMillis() - dateFormat.parse(loveday).getTime();
    35. days = (int) (time / (24*60*60*1000));
    36. } catch (ParseException e) {
    37. e.printStackTrace();
    38. }
    39. return days;
    40. }
    41. }

    3.封装推送逻辑

    3.1 封装配置类

    1. @Component
    2. public class WeChatConfigure {
    3. public static String Access_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}";
    4. public static String Send_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={0}";
    5. public static String App_ID;
    6. @Value("${WeChat.AppID}")
    7. public void setAppID(String AppID) {
    8. App_ID = AppID;
    9. }
    10. public static String App_Secret;
    11. @Value("${WeChat.AppSecret}")
    12. public void setAppSecret(String AppSecret) {
    13. App_Secret = AppSecret;
    14. }
    15. public static String Open_ID;
    16. @Value("${WeChat.OpenID}")
    17. public void setOpenID(String OpenID) {
    18. Open_ID = OpenID;
    19. }
    20. public static String Template_ID;
    21. @Value("${WeChat.TemplateID}")
    22. public void setTemplateID(String TemplateID) {
    23. Template_ID = TemplateID;
    24. }
    25. public static String Top_Color;
    26. @Value("${WeChat.TopColor}")
    27. public void setTopColor(String TopColor) {
    28. Top_Color = TopColor;
    29. }
    30. public static String Weather_API;
    31. @Value("${WeChat.WeatherAPI}")
    32. public void setWeatherAPI(String WeatherAPI) {
    33. Weather_API = WeatherAPI;
    34. }
    35. public static String Rainbow_API;
    36. @Value("${WeChat.RainbowAPI}")
    37. public void setRainbowAPI(String RainbowAPI) {
    38. Rainbow_API = RainbowAPI;
    39. }
    40. public static String Boy_Birthday;
    41. @Value("${WeChat.BoyBirthday}")
    42. public void setBoyBirthday(String BoyBirthday) {
    43. Boy_Birthday = BoyBirthday;
    44. }
    45. public static String Girl_Birthday;
    46. @Value("${WeChat.GirlBirthday}")
    47. public void setGirlBirthday(String GirlBirthday) {
    48. Girl_Birthday = GirlBirthday;
    49. }
    50. public static String Love_Day;
    51. @Value("${WeChat.LoveDay}")
    52. public void setLoveDay(String LoveDay) {
    53. Love_Day = LoveDay;
    54. }
    55. }

    3.2 封装实体类

    1. //单条数据Item封装
    2. public class DataItem {
    3. private String value;
    4. private String color;
    5. public DataItem(String _value, String _color) {
    6. this.value = _value;
    7. this.color = _color;
    8. }
    9. public String getValue() {
    10. return value;
    11. }
    12. public void setValue(String value) {
    13. this.value = value;
    14. }
    15. public String getColor() {
    16. return color;
    17. }
    18. public void setColor(String color) {
    19. this.color = color;
    20. }
    21. }
    22. //发送数据集result封装
    23. public class ResultVo {
    24. private String touser;
    25. private String template_id;
    26. private String topcolor;
    27. private HashMap data;
    28. private ResultVo(String _touser, String _template_id, String _topcolor, HashMap _data) {
    29. this.touser = _touser;
    30. this.template_id = _template_id;
    31. this.topcolor = _topcolor;
    32. this.data = _data;
    33. }
    34. public String getTouser() {
    35. return touser;
    36. }
    37. public String getTemplate_id() {
    38. return template_id;
    39. }
    40. public String getTopcolor() {
    41. return topcolor;
    42. }
    43. public HashMap getData() {
    44. return data;
    45. }
    46. public static ResultVo initializeResultVo(String _touser, String _template_id, String _topcolor){
    47. return new ResultVo(_touser,_template_id,_topcolor,null);
    48. }
    49. public static ResultVo initializeResultVo(String _touser, String _template_id, String _topcolor,HashMap _data){
    50. return new ResultVo(_touser,_template_id,_topcolor,_data);
    51. }
    52. public ResultVo setAttribute(String key, DataItem item){
    53. if(this.data==null)this.data = new HashMap();
    54. this.data.put(key,item);
    55. return this;
    56. }
    57. }

    3.3 推送逻辑Controller实现

    1. @Controller
    2. public class WeChatController {
    3. @Autowired
    4. RestTemplate restTemplate;
    5. /**
    6. * {{date.DATA}}
    7. * {{remark.DATA}}
    8. * 所在城市:{{city.DATA}}
    9. * 今日天气:{{weather.DATA}}
    10. * 气温变化:{{min_temperature.DATA}} ~ {{max_temperature.DATA}}
    11. * 今日建议:{{tips.DATA}}
    12. * 今天是我们恋爱的第 {{love_days.DATA}} 天
    13. * 距离xx生日还有 {{girl_birthday.DATA}} 天
    14. * 距离xx生日还有 {{boy_birthday.DATA}} 天
    15. * {{rainbow.DATA}}
    16. */
    17. public void push(){
    18. ResultVo resultVo = ResultVo.initializeResultVo(WeChatConfigure.Open_ID,WeChatConfigure.Template_ID,WeChatConfigure.Top_Color);
    19. //1.设置城市与天气信息
    20. Weather weather = DataUtils.getWeather(restTemplate);
    21. resultVo.setAttribute("date",new DataItem(weather.getDate() + " " + weather.getWeek(),"#00BFFF"));
    22. resultVo.setAttribute("city",new DataItem(weather.getArea(),null));
    23. resultVo.setAttribute("weather",new DataItem(weather.getWeather(),"#1f95c5"));
    24. resultVo.setAttribute("min_temperature",new DataItem(weather.getLowest(),"#0ace3c"));
    25. resultVo.setAttribute("max_temperature",new DataItem(weather.getHighest(),"#dc1010"));
    26. resultVo.setAttribute("tips",new DataItem(weather.getTips(),null));
    27. //2.设置日期相关
    28. int love_days = DataUtils.getLoveDays(WeChatConfigure.Love_Day);
    29. int girl_birthday = DataUtils.getBirthDays(WeChatConfigure.Girl_Birthday);
    30. int boy_birthday = DataUtils.getBirthDays(WeChatConfigure.Boy_Birthday);
    31. resultVo.setAttribute("love_days",new DataItem(love_days+"","#FFA500"));
    32. resultVo.setAttribute("girl_birthday",new DataItem(girl_birthday+"","#FFA500"));
    33. resultVo.setAttribute("boy_birthday",new DataItem(boy_birthday+"","#FFA500"));
    34. //3.设置彩虹屁
    35. String rainbow = DataUtils.getRainbow(restTemplate);
    36. resultVo.setAttribute("rainbow",new DataItem(rainbow,"#FF69B4"));
    37. //4.其他
    38. String remark = "❤";
    39. if(DataUtils.getBirthDays(WeChatConfigure.Love_Day) == 0){
    40. remark = "今天是恋爱周年纪念日!永远爱你~";
    41. }else if(girl_birthday == 0){
    42. remark = "今天是xx宝贝的生日!生日快乐哟~";
    43. }else if(boy_birthday == 0){
    44. remark = "今天是xx的生日!别忘了好好爱他~";
    45. }
    46. resultVo.setAttribute("remark",new DataItem(remark,"#FF1493"));
    47. //5.发送请求,推送消息
    48. String responseStr = restTemplate.postForObject(WeChatConfigure.Send_URL, resultVo, String.class, DataUtils.getAccessToken(restTemplate));
    49. printPushLog(responseStr);
    50. }
    51. /**
    52. * 打印 response log
    53. * @param responseStr
    54. */
    55. private void printPushLog(String responseStr){
    56. JSONObject jsonObject = JSONObject.parseObject(responseStr);
    57. String msgCode = jsonObject.getString("errcode");
    58. String msgContent = jsonObject.getString("errmsg");
    59. SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    60. System.out.println("[ " + dateFormat.format(new Date()) + " ] : messageCode=" + msgCode + ",messageContent=" + msgContent);
    61. }
    62. }

    4.封装定时任务

    1. @Component
    2. public class PushTask {
    3. @Autowired
    4. WeChatController weChatController;
    5. //每日 早上9点 定时推送
    6. @Scheduled(cron = "0 0 9 * * ?")
    7. public void scheduledPush(){
    8. weChatController.push();
    9. }
    10. }

    5.打包部署腾讯云

            项目打包成 jar 包后传到腾讯云服务器上,直接运行即可实现每日推送。

    1. #nohup指令 后台启动jar包,日志信息输出到log.file文件
    2. nohup java -jar xxx-0.0.1-SNAPSHOT.jar > log.file 2>&1 &

  • 相关阅读:
    HTML:网页设计案例4
    python练习题(慕课配套,三四五章)
    网页设计成品DW静态网页Html5响应式css3 (餐厅 6页 带轮播图)
    同花顺_代码解析_技术指标_V,W
    Django视图层模版层全面解析全网最细的教程
    QT 音乐播放器【二】 歌词同步+滚动+特效
    【大咖说Ⅰ】北邮博导石川教授:图机器学习及其应用
    用huggingface.Accelerate进行分布式训练
    如何看待2023年大量劝入C++?
    如何将Docker与Kubernetes集成,实现云原生应用程序
  • 原文地址:https://blog.csdn.net/qq_40772692/article/details/126693268