首页 > 其他分享 >开发企业微信群机器人,实现定时提醒

开发企业微信群机器人,实现定时提醒

时间:2023-11-13 17:01:24浏览次数:29  
标签:String 微信群 机器人 webhook 消息 定时 public SDK

大家好,我是鱼皮,今天分享一个用程序解决生活工作问题的真实案例。

说来惭愧,事情是这样的,在我们公司,每天都要轮流安排一名员工(当然也包括我)去楼层中间一个很牛的饮水机那里接水。但由于大家每天都有自己的工作,经常出现忘记接水的情况,导致大家口渴难耐。

怎么解决这个问题呢?

我想到了几种方法:

1)每天大家轮流提醒。但是别说提醒别人了,自己都不记得什么时候轮到自己接水。

2)由一个员工负责提醒大家接水,必要时招募一个 “接水提醒员”。

3)在企业微信的日历功能给员工安排接水日程,就像下面这样:

开发企业微信群机器人,实现定时提醒_计算机

但问题是我们的人数和天数不是完全对应的、反复安排日程也很麻烦。

你觉得上面哪种方案好呢?其实我觉得第二个方案是最好的 —— 招募一个 “接水提醒员”。

别笑,我认真的!

只不过这个 “接水提醒员” 何必是人?

没错,作为一名程序员,我们可以搞一个机器人,让它在企业微信群聊中每天提醒不同的员工去接水即可。

其实这个功能和员工排班打卡系统是很类似的,只不过更轻量一些。我也调研了很多排班系统,但是都要收费,索性自己开发一个好了。

在企业微信中接入机器人其实非常简单,因为企业微信官方就支持群聊机器人功能,所以这次的任务我就安排给了实习生,他很快就完成了,所以我相信大家应该也都能学会~

企微群聊机器人开发

学习开发第三方应用时,一定要先完整阅读官方文档,比如企业微信群机器人配置文档。

指路:https://developer.work.weixin.qq.com/document/path/99110

开发企业微信群机器人,实现定时提醒_编程_02

设计 SDK 结构

虽然我们的目标是做一个提醒接水机器人,但是企业微信群聊机器人其实是一个通用的功能,所以我们决定开发一个企微机器人 SDK,以后公司其他业务需要时都能够快速复用。(比如开发一个定时喝水提醒机器人)

设计好 SDK 是需要一定技巧的,之前给大家分享过:如何设计一个优秀的 SDK ,可以阅读参考。

在查阅企微机器人文档后,了解到企业微信机器人支持发送多种类型的消息,包括文本、 Markdown 、图片、图文、文件、语音和模块卡片等,文档中对每一种类型的请求参数和字段含义都做了详尽的解释。

吐槽一下,跟微信开发者文档比起来,企微机器人的文档写得清晰多了!

开发企业微信群机器人,实现定时提醒_计算机_03

企微文本消息格式

由于每种消息最终都是要转换成 JSON 格式作为 HTTP 请求的参数的,所以我们可以设计一个基础的消息类(Message)来存放公共参数,然后定义各种不同的具体消息类来集成它(比如文本消息 TextMessage、Markdown 消息 MarkdownMessage 等)。

为了简化开发者使用 SDK 来发送消息,定义统一的 MessageSender 类,在类中提供发送消息的方法(比如发送文本消息 sendText),可以接受 Message 并发送到企业微信服务器。

最终,客户端只需调用统一的消息发送方法即可。SDK 的整体结构如下图所示:

开发企业微信群机器人,实现定时提醒_计算机_04

值得一提的是,如果要制作更通用的消息发送 SDK。可以将 MessageSender 定义成接口,编写不同的子类比如飞书 MessageSender、短信 MessageSender 等。

开发 SDK

做好设计之后,接下来就可以开始开发 SDK 了。

步骤如下:

  1. 获取 webhook
  2. 创建 SDK 项目
  3. 编写代码
  4. SDK 打包
  5. 调用 SDK

1、获取 webhook

首先,必须在企业微信群聊中创建一个企业微信机器人,并获取机器人的 webhook。

webhook 是一个 url 地址,用于接受我们开发者自己服务器的请求,从而控制企业微信机器人。后续所有的开发过程,都需要通过 webhook 才可以实现。

开发企业微信群机器人,实现定时提醒_编程_05

复制并保存好这个 Webhook 地址,注意不要泄露该地址!

开发企业微信群机器人,实现定时提醒_spring_06

2、创建 SDK 项目

SDK 通常是一个很干净的项目,此处我们使用 Maven 来构建一个空的项目,并在 pom.xml 文件中配置项目信息。

需要特别注意的是,既然我们正在创建一个 SDK,这意味着它将被更多的开发者使用。因此,在配置 groupId 和 artifactId 时,我们应当遵循以下规范:

  • groupId:它是项目组织或项目开发者的唯一标识符,其实际对应的是 main 目录下的 Java 目录结构。
  • artifactId:它是项目的唯一标识符,对应的是项目名称,即项目的根目录名称。通常,它应当为纯小写,并且多个词之间使用中划线(-)隔开。
  • version:它指定了项目的当前版本。其中,SNAPSHOT 表示该项目仍在开发中,是一个不稳定的版本。

以下是我们配置好的项目信息:

<groupId>com.yupi</groupId>
<artifactId>rtx-robot</artifactId>
<version>1.0-SNAPSHOT</version>

为了让我们的项目更加易用,我们还要能做到让开发者通过配置文件来传入配置(比如 webhook),而不是通过硬编码重复配置各种信息。

所以此处我们把项目只作为 Spring Boot 的 starter,需要在 pom.xml 文件中引入依赖:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-configuration-processor</artifactId>
  <optional>true</optional>
</dependency>

最后,我们还需要添加一个配置,配置项 <skip>true</skip> 表示跳过执行该插件的默认行为:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <skip>true</skip>
            </configuration>
        </plugin>
    </plugins>
</build>

这样,一个 SDK 项目的初始依赖就配置好了。

3、编写配置类

现在我们就可以按照之前设计的结构开发了。

首先,我们要写一个配置类,用来接受开发者在配置文件中写入的 webhook。

同时,我们可以在配置类中,将需要被调用的 MessageSender 对象 Bean 自动注入到 IOC 容器中,不用让开发者自己 new 对象了。

示例代码如下:

@Configuration
@ConfigurationProperties(prefix = "wechatwork-bot")
@ComponentScan
@Data
public class WebhookConfig {

    private String webhook;

    @Bean
    public RtxRobotMessageSender rtxRobotMessageSender() {
        return new RtxRobotMessageSender(webhook);
    }
}

接下来,为了让 Spring Boot 项目在启动时能自动识别并应用配置类,需要把配置类写入到 resources/META-INF/spring.factories 文件中,示例代码如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.yupi.rtxrobot.config.WebhookConfig

4、编写消息类

接下来,我们要按照官方文档的请求参数把几种类型的消息对象编写好。

由于每个消息类都有一个固定的字段 msgtype,所以我们定义一个基类 Message,方便后续将不同类型的消息传入统一的方法:

public class Message {

    /**
     * 消息类型
     **/
    String msgtype;
}

接下来编写具体的消息类,比如纯文本类型消息 TextMessage,示例代码如下:

@Data
public class TextMessage extends Message {

    /**
     * 消息内容
     */
    private String content;

    /**
     * 被提及者userId列表
     */
    private List<String> mentionedList;

    /**
     * 被提及者电话号码列表
     */
    private List<String> mentionedMobileList;
  
    /**
     * 提及全体
     */
    private Boolean mentionAll = false;

    public TextMessage(String content, List<String> mentionedList, List<String> mentionedMobileList, Boolean mentionAll) {
        this.content = content;
        this.mentionedList = mentionedList;
        this.mentionedMobileList = mentionedMobileList;
        this.mentionAll = mentionAll;

        if (mentionAll) {
            if (CollUtil.isNotEmpty(this.mentionedList) || CollUtil.isNotEmpty(this.mentionedMobileList)) {
                if (CollUtil.isNotEmpty(mentionedList)) {
                    this.mentionedList.add("@all");
                } else {
                    this.mentionedList = CollUtil.newArrayList("@all");
                }
            } else {
                this.mentionedList = CollUtil.newArrayList("@all");
            }
        }
    }

    public TextMessage(String content) {
        this(content, null, null, false);
    }
}

上面的代码中,有个代码优化小细节,官方文档是使用 “@all” 字符串来表示 @全体成员的,但 “@all” 是一个魔法值,为了简化调用,我们将其封装为 mentionAll 布尔类型字段,并且在构造函数中自动转换为实际请求需要的字段。

5、编写消息发送类

接下来,我们将编写一个消息发送类。在这个类中,定义了用于发送各种类型消息的方法,并且所有的方法都会依赖调用底层的 send 方法。send 方法的作用是通过向企微机器人的 webhook 地址发送请求,从而驱动企微机器人发送消息。

以下是示例代码,有很多编码细节:

/**
 * 微信机器人消息发送器
 * @author yuyuanweb
 */
@Slf4j
@Data
public class RtxRobotMessageSender {

    private final String webhook;
  
    public WebhookConfig webhookConfig;

    public RtxRobotMessageSender(String webhook) {
        this.webhook = webhook;
    }

    /**
     * 支持自定义消息发送
     */
    public void sendMessage(Message message) throws Exception {
        if (message instanceof TextMessage) {
            TextMessage textMessage = (TextMessage) message;
            send(textMessage);
        } else if (message instanceof MarkdownMessage) {
            MarkdownMessage markdownMessage = (MarkdownMessage) message;
            send(markdownMessage);
        } else {
            throw new RuntimeException("Unsupported message type");
        }
    }

    /**
     * 发送文本(简化调用)
     */ 
    public void sendText(String content) throws Exception {
        sendText(content, null, null, false);
    }
  
    public void sendText(String content, List<String> mentionedList, List<String> mentionedMobileList) throws Exception {
        TextMessage textMessage = new TextMessage(content, mentionedList, mentionedMobileList, false);
        send(textMessage);
    }
    
    /**
     * 发送消息的公共依赖底层代码
     */
    private void send(Message message) throws Exception {
        String webhook = this.webhook;
        String messageJsonObject = JSONUtil.toJsonStr(message);
       // 未传入配置,降级为从配置文件中寻找
        if (StrUtil.isBlank(this.webhook)) {
            try {
                webhook = webhookConfig.getWebhook();
            } catch (Exception e) {
                log.error("没有找到配置项中的webhook,请检查:1.是否在application.yml中填写webhook 2.是否在spring环境下运行");
                throw new RuntimeException(e);
            }
        }
        OkHttpClient client = new OkHttpClient();
        RequestBody body = RequestBody.create(
                MediaType.get("application/json; charset=utf-8"),
                messageJsonObject);
        Request request = new Request.Builder()
                .url(webhook)
                .post(body)
                .build();
        try (Response response = client.newCall(request).execute()) {
            if (response.isSuccessful()) {
                log.info("消息发送成功");
            } else {
                log.error("消息发送失败,响应码:{}", response.code());
                throw new Exception("消息发送失败,响应码:" + response.code());
            }
        } catch (IOException e) {
            log.error("发送消息时发生错误:" + e);
            throw new Exception("发送消息时发生错误", e);
        }
    }
}

代码部分就到这里,是不是也没有很复杂?

6、SDK 打包

接下来就可以对 SDK 进行打包,然后本地使用或者上传到远程仓库了。

SDK 的打包非常简单,通过 Maven 的 install 命令即可,SDK 的 jar 包就会被导入到你的本地仓库中。

在打包前建议先执行 clean 来清理垃圾文件。

开发企业微信群机器人,实现定时提醒_微信_07

7、调用 SDK

最后我们来调用自己写的 SDK,首先将你的 SDK 作为依赖引入到项目中,比如我们的接水提醒应用。

引入代码如下:

<dependency>
  <groupId>com.yupi</groupId>
  <artifactId>rtx-robot</artifactId>
  <version>1.0-SNAPSHOT</version>
</dependency>

然后将之前复制的 webhook 写入到 Spring Boot 的配置文件中:

wechatwork-bot:
  webhook: 你的webhook地址

随后你就可以用依赖注入的方式得到一个消息发送者对象了:

@Resource
public RtxRobotMessageSender rtxRobotMessageSender;

当然你也可以选择在一个非 Spring 环境中手动创建对象,自己传入 webhook:

String webhook = "你的webhook地址";
RtxRobotMessageSender rtxRobotMessageSender = new RtxRobotMessageSender(webhook);

现在,就可以轻松实现我们之前提到的提醒接水工具了。

这里我们就用最简单的方式,定义一个员工数组,分别对应到每周 X,然后用定时任务每日执行消息发送。

示例代码如下:

@Component
public class WaterReminderTask {

    @Resource
    public RtxRobotMessageSender rtxRobotMessageSender;

    private String[] names = {"员工a", "员工b", "员工c", "员工d", "员工e"};

    @Scheduled(cron = "0 55 9 * * MON-FRI")
    public void remindToGetWater() {
        LocalDate today = LocalDate.now();
        DayOfWeek dayOfWeek = today.getDayOfWeek();
        String nameToRemind;
        switch (dayOfWeek) {
            case MONDAY:
                nameToRemind = names[0];
                break;
            case TUESDAY:
                nameToRemind = names[1];
                break;
            case WEDNESDAY:
                nameToRemind = names[2];
                break;
            case THURSDAY:
                nameToRemind = names[3];
                break;
            case FRIDAY:
                nameToRemind = names[4];
                break;
            default:
                return;
        }
      
        String message = "提醒:" + nameToRemind + ",是你接水的时间了!";
        rtxRobotMessageSender.sendText(message);
    }
}

好了,现在大家每天都有水喝了,真不错

标签:String,微信群,机器人,webhook,消息,定时,public,SDK
From: https://blog.51cto.com/u_15016006/8346541

相关文章

  • ansible性能巡检+定时任务执行shell脚本
    一、ansible_使用ansible+shell脚本进行环境巡检1.编写脚本#用户目录下执行cd~#编辑vicheck.sh实现效果:脚本内容:巡检指标1:cpu使用率大于70,输出unhealth巡检指标2:内存使用率大于70,输出unhealth巡检指标3:/picclife磁盘使用率大于70,输出unhealth#!/bin/bash#cpu巡检sar......
  • Go实现Zabbix企业微信机器人告警
    企业微信应用通知的程序相对复杂点,见上篇文章机器人告警相对简单点,只需一个url即可企业微信里创建一个机器人注意机器人的url,后续程序中需要使用直接上程序sjgzbx_machine.gopackagemainimport("bytes""encoding/json""fmt""io/ioutil""net/ht......
  • 使用ResponseSelector实现校园招聘FAQ机器人
      本文主要介绍使用ResponseSelector实现校园招聘FAQ机器人,回答面试流程和面试结果查询的FAQ问题。FAQ机器人功能分为业务无关的功能和业务相关的功能2类。一.data/nlu.yml文件  与普通意图相比,ResponseSelector训练数据中的意图采用group/intent格式(检索意图)。比如,普通意图......
  • wechaty撸一个属于自己的微信机器人(Python版接入文心一言)
    前言说明:机器人的框架找了很久,由于很多框架都不能使用了或者封号率极高,最后选择了wewechaty,wechaty是可以使用ipad协议,主要是以node写的,因为打算机器人接入爬虫项目,所以特意用了python版本,对于python版网上教程太少且模糊且时间过于久远,所做以此文为采坑记录。前期准备:tok......
  • Timer是jdk中提供的一个定时器工具,TImer用法
    说到任务调度,大家可能会想到Quartz框架,但是jdk自带的简单任务调度工具类,反而了解的人并不是很多。我觉得如果你的业务相对简单的话,没必要非得用Quartz等框架,使用Timer完全可以胜任的。简单来分享一下我了解的Timer。Timer是jdk中提供的一个定时器工具,使用的时候会在主线程之外起......
  • ubuntu 配置NTP时间服务器&&定时同步本地时间
     Ubuntu系统:NTP时间服务器的安装:服务器安装命令:sudoapt-getinstallntp   NTP服务配置,设置为本地时间服务器,屏蔽默认server,服务器层级设为10:vim/etc/ntp.conf删除掉原有的serverxxx.xxx.xxx.xxx信息:server127.127.1.0fudge127.127.1.0stratum10  ......
  • JavaScript--定时器案例
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>Document</title><......
  • windows服务器中Oracle数据库定时备份
    脚本准备remdelete10daysfilesforfiles/p"文件路径"/d-10/c"cmd/cechodeleting@file...&&del/f@path"remexpdpszsetsz_file=备份文件名字%date:~0,4%%date:~5,2%%date:~8,2%expdp数据库用户名/数据库密码@数据库实例名directory=路径对象dumpfile......
  • 直播系统源代码,实现倒计时,定时任务
    直播系统源代码,实现倒计时,定时任务1.使用CountDownTimer类: valcountDownTimer=object:CountDownTimer(30000,1000){  overridefunonTick(millisUntilFinished:Long){    //在倒计时的过程中,每秒钟会执行一次该方法    valsecondsRemainin......
  • 天才少年稚晖君智元机器人走路进场!AI模型做大脑,目标售价20万以内
    文丨Congerry在吗,抽个机器人?8月14日,前“华为天才少年”稚晖君在社交媒体官宣智元人形机器人。今天,它就来了,稚晖君正式发布智元具身智能机器人远征A1。身高175cm,体重53kg,最高步速为7km/h,全身49个自由度,整机承重80kg,单臂最大负载5kg。不仅如此,远征A1还集成了大模型,拥有智能交互、决策......