The Java WeChat public account automatically sends greetings to girlfriends every day

        Recently, there has been a trend of doing WeChat public account pushes for girlfriends on the Internet, so my girlfriends who others have must also have Oo. I briefly researched the principle of doing WeChat public account pushes. Simply put, the background server makes a timer task, and then periodically call the Web API interface (HTTP) provided by the WeChat public platform, and send the template message (JSON data). The technology stack and development process are summarized as follows:

  • Front end: WeChat public account-subscription account-test account
  • Backend: SpringBoot + RestTemplate

 1. Configure the WeChat public platform test account

        Click to open the WeChat public platform link (  WeChat public platform  ), register and apply for a WeChat public test account. The test account can experience all the functional API interfaces of the WeChat public platform. We mainly use the template message push API here. However, the limitation of the test account is that only the default official account name can be used and the function may be taken off the shelves at any time . If conditions permit, you can apply for an enterprise subscription account/service account (personally certified subscription accounts do not have template message push API permissions, and only enterprises can authenticate service accounts). The following parts are more important in the test number configuration (refer to the development document template message | WeChat open document (qq.com) ):

  • Test number information: including appID and appsecret, used to obtain Token and API interface for identity verification

  • User list: used to obtain the openId of the subscribed user and push it to the target user (you must follow this subscription number first)

  • Template message interface: used to configure the pushed message template, including template ID (for interface calling), template content, etc. Parameters can be set in the template content (template titles are not allowed), which are used when calling the interface. The parameters need to be configured in the format of { {params.DATA}} . Among them, params is the name of the corresponding JSON data variable transmitted from the backend server, and DATA is the fixed syntax of the frontend template message.

  

    //JSON数据传输格式示例
    {
           "touser":"OPENID",
           "template_id":"ngqIpbwh8bUfcSsECmogfXcV14J0tQlEpBO27izEYtY",
           "topcolor":"#FF0000",
           "data":{
                   "date": {
                       "value":"2022-09-04 星期日",
                       "color":"#173177"
                   },
                   "remark":{
                       "value":"♥",
                       "color":"#173177"
                   },
                   "city": {
                       "value":"北京",
                       "color":"#173177"
                   },
                   "weather": {
                       "value":"多云转晴",
                       "color":"#173177"
                   },
                   ...
           }
       }

2. Data interface encapsulation

        In the message push template, the data we need to use includes climate (weather, temperature, city, etc.), dating days, birthday countdown days, and rainbow fart sentences. The data acquisition methods are as follows:

2.1 Encapsulation of Tianxing data interface

        The acquisition of Tianxing interface data is also to obtain the data (RestTemplate) in the response by sending a request through the Web API. The interface document is as follows:

public class DataUtils {

    /**
     * 获取 Weather 信息
     * @param restTemplate
     * @return
     */
    public static Weather getWeather(RestTemplate restTemplate){
        String responseJson = restTemplate.getForObject(WeChatConfigure.Weather_API, String.class);
        JSONObject responseResult = JSONObject.parseObject(responseJson);
        JSONObject jsonObject = responseResult.getJSONArray("newslist").getJSONObject(0);
        return jsonObject.toJavaObject(Weather.class);
    }

    /**
     * 获取 RainbowPi 信息
     * @param restTemplate
     * @return
     */
    public static String getRainbow(RestTemplate restTemplate){
        String responseJson = restTemplate.getForObject(WeChatConfigure.Rainbow_API, String.class);
        JSONObject responseResult = JSONObject.parseObject(responseJson);
        JSONObject jsonObject = responseResult.getJSONArray("newslist").getJSONObject(0);
        return jsonObject.getString("content");
    }

}

 2.2 Package of date calculation tool

        The logic of calculating birthday countdown and calculating the number of days in love is different. Calculating the birthday countdown needs to determine whether the birthday date has passed, but calculating the number of days in love is relatively simple, just count the time directly.

public class DataUtils {

    /**
     * 计算生日天数 days
     * @return
     */
    public static int getBirthDays(String birthday) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cToday = Calendar.getInstance(); // 存今天
        Calendar cBirth = Calendar.getInstance(); // 存生日
        int days = 0;
        try {
            cBirth.setTime(dateFormat.parse(birthday)); // 设置生日
            cBirth.set(Calendar.YEAR, cToday.get(Calendar.YEAR)); // 修改为本年
            if (cBirth.get(Calendar.DAY_OF_YEAR) < cToday.get(Calendar.DAY_OF_YEAR)) {
                // 生日已经过了,要算明年的了
                days = (cToday.getActualMaximum(Calendar.DAY_OF_YEAR) - cToday.get(Calendar.DAY_OF_YEAR)) + cBirth.get(Calendar.DAY_OF_YEAR);
            } else {
                // 生日还没过
                days = cBirth.get(Calendar.DAY_OF_YEAR) - cToday.get(Calendar.DAY_OF_YEAR);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return days;
    }

    /**
     * 计算恋爱天数 days
     * @return
     */
    public static int getLoveDays(String loveday){
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        int days = 0;
        try {
            long time = System.currentTimeMillis() - dateFormat.parse(loveday).getTime();
            days = (int) (time / (24*60*60*1000));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return days;
    }

}

3. Encapsulate push logic

3.1 Package configuration class

@Component
public class WeChatConfigure {

    public static String Access_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}";
    public static String Send_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={0}";

    public static String App_ID;
    @Value("${WeChat.AppID}")
    public void setAppID(String AppID) {
        App_ID = AppID;
    }

    public static String App_Secret;
    @Value("${WeChat.AppSecret}")
    public void setAppSecret(String AppSecret) {
        App_Secret = AppSecret;
    }

    public static String Open_ID;
    @Value("${WeChat.OpenID}")
    public void setOpenID(String OpenID) {
        Open_ID = OpenID;
    }

    public static String Template_ID;
    @Value("${WeChat.TemplateID}")
    public void setTemplateID(String TemplateID) {
        Template_ID = TemplateID;
    }

    public static String Top_Color;
    @Value("${WeChat.TopColor}")
    public void setTopColor(String TopColor) {
        Top_Color = TopColor;
    }

    public static String Weather_API;
    @Value("${WeChat.WeatherAPI}")
    public void setWeatherAPI(String WeatherAPI) {
        Weather_API = WeatherAPI;
    }

    public static String Rainbow_API;
    @Value("${WeChat.RainbowAPI}")
    public void setRainbowAPI(String RainbowAPI) {
        Rainbow_API = RainbowAPI;
    }

    public static String Boy_Birthday;
    @Value("${WeChat.BoyBirthday}")
    public void setBoyBirthday(String BoyBirthday) {
        Boy_Birthday = BoyBirthday;
    }

    public static String Girl_Birthday;
    @Value("${WeChat.GirlBirthday}")
    public void setGirlBirthday(String GirlBirthday) {
        Girl_Birthday = GirlBirthday;
    }

    public static String Love_Day;
    @Value("${WeChat.LoveDay}")
    public void setLoveDay(String LoveDay) {
        Love_Day = LoveDay;
    }
}

3.2 Encapsulating Entity Classes

//单条数据Item封装
public class DataItem {

    private String value;
    private String color;

    public DataItem(String _value, String _color) {
        this.value = _value;
        this.color = _color;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

//发送数据集result封装
public class ResultVo {
    private String touser;
    private String template_id;
    private String topcolor;
    private HashMap<String, DataItem> data;

    private ResultVo(String _touser, String _template_id, String _topcolor, HashMap<String, DataItem> _data) {
        this.touser = _touser;
        this.template_id = _template_id;
        this.topcolor = _topcolor;
        this.data = _data;
    }

    public String getTouser() {
        return touser;
    }

    public String getTemplate_id() {
        return template_id;
    }

    public String getTopcolor() {
        return topcolor;
    }

    public HashMap<String, DataItem> getData() {
        return data;
    }

    public static ResultVo initializeResultVo(String _touser, String _template_id, String _topcolor){
        return new ResultVo(_touser,_template_id,_topcolor,null);
    }

    public static ResultVo initializeResultVo(String _touser, String _template_id, String _topcolor,HashMap<String, DataItem> _data){
        return new ResultVo(_touser,_template_id,_topcolor,_data);
    }

    public ResultVo setAttribute(String key, DataItem item){
        if(this.data==null)this.data = new HashMap<String,DataItem>();
        this.data.put(key,item);
        return this;
    }
}

3.3 Push Logic Controller Implementation

@Controller
public class WeChatController {

    @Autowired
    RestTemplate restTemplate;

    /**
     * {
   
   {date.DATA}}
     * {
   
   {remark.DATA}}
     * 所在城市:{
   
   {city.DATA}}
     * 今日天气:{
   
   {weather.DATA}}
     * 气温变化:{
   
   {min_temperature.DATA}} ~ {
   
   {max_temperature.DATA}}
     * 今日建议:{
   
   {tips.DATA}}
     * 今天是我们恋爱的第 {
   
   {love_days.DATA}} 天
     * 距离xx生日还有 {
   
   {girl_birthday.DATA}} 天
     * 距离xx生日还有 {
   
   {boy_birthday.DATA}} 天
     * {
   
   {rainbow.DATA}}
     */
    public void push(){
        ResultVo resultVo = ResultVo.initializeResultVo(WeChatConfigure.Open_ID,WeChatConfigure.Template_ID,WeChatConfigure.Top_Color);
        //1.设置城市与天气信息
        Weather weather = DataUtils.getWeather(restTemplate);
        resultVo.setAttribute("date",new DataItem(weather.getDate() + " " + weather.getWeek(),"#00BFFF"));
        resultVo.setAttribute("city",new DataItem(weather.getArea(),null));
        resultVo.setAttribute("weather",new DataItem(weather.getWeather(),"#1f95c5"));
        resultVo.setAttribute("min_temperature",new DataItem(weather.getLowest(),"#0ace3c"));
        resultVo.setAttribute("max_temperature",new DataItem(weather.getHighest(),"#dc1010"));
        resultVo.setAttribute("tips",new DataItem(weather.getTips(),null));
        //2.设置日期相关
        int love_days = DataUtils.getLoveDays(WeChatConfigure.Love_Day);
        int girl_birthday = DataUtils.getBirthDays(WeChatConfigure.Girl_Birthday);
        int boy_birthday = DataUtils.getBirthDays(WeChatConfigure.Boy_Birthday);
        resultVo.setAttribute("love_days",new DataItem(love_days+"","#FFA500"));
        resultVo.setAttribute("girl_birthday",new DataItem(girl_birthday+"","#FFA500"));
        resultVo.setAttribute("boy_birthday",new DataItem(boy_birthday+"","#FFA500"));
        //3.设置彩虹屁
        String rainbow =  DataUtils.getRainbow(restTemplate);
        resultVo.setAttribute("rainbow",new DataItem(rainbow,"#FF69B4"));
        //4.其他
        String remark = "❤";
        if(DataUtils.getBirthDays(WeChatConfigure.Love_Day) == 0){
            remark = "今天是恋爱周年纪念日!永远爱你~";
        }else if(girl_birthday == 0){
            remark = "今天是xx宝贝的生日!生日快乐哟~";
        }else if(boy_birthday == 0){
            remark = "今天是xx的生日!别忘了好好爱他~";
        }
        resultVo.setAttribute("remark",new DataItem(remark,"#FF1493"));
        //5.发送请求,推送消息
        String responseStr = restTemplate.postForObject(WeChatConfigure.Send_URL, resultVo, String.class, DataUtils.getAccessToken(restTemplate));
        printPushLog(responseStr);
    }

    /**
     * 打印 response log
     * @param responseStr
     */
    private void printPushLog(String responseStr){
        JSONObject jsonObject = JSONObject.parseObject(responseStr);
        String msgCode = jsonObject.getString("errcode");
        String msgContent = jsonObject.getString("errmsg");
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("[ " + dateFormat.format(new Date()) + " ] : messageCode=" + msgCode + ",messageContent=" + msgContent);
    }
}

4. Encapsulate timing tasks

@Component
public class PushTask {

    @Autowired
    WeChatController weChatController;

    //每日 早上9点 定时推送
    @Scheduled(cron = "0 0 9 * * ?")
    public void scheduledPush(){
        weChatController.push();
    }
}

5. Package and deploy Tencent Cloud

        The project is packaged into a jar package and then uploaded to the Tencent cloud server, and the daily push can be realized by running it directly.

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

Guess you like

Origin blog.csdn.net/qq_40772692/article/details/126693268