飞书机器人消息推送策略模式Java实践

在现代企业应用开发中,及时准确的消息通知机制至关重要。本文将介绍一种基于策略模式的飞书机器人消息推送实现方案,帮助开发者快速集成多种消息推送场景。

设计理念

我们的解决方案采用了策略模式,通过抽象基类 AbstractFeishuMessageStrategy 统一处理消息发送的核心逻辑,而具体的策略实现类则专注于配置差异化的 webhook 地址。

核心组件解析

  1. 抽象基类 AbstractFeishuMessageStrategy

AbstractFeishuMessageStrategy 是整个消息推送框架的核心,它提供了统一的消息发送机制和三种标准消息类型的构建方法。

java 复制代码
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 飞书消息推送抽象策略基类
 * 提供统一的消息发送逻辑和标准消息构建方法
 */
@Slf4j
public abstract class AbstractFeishuMessageStrategy {
    /**
     * 获取飞书机器人webhook地址
     * 子类必须实现此方法提供具体的webhook地址
     * 
     * @return webhook地址
     */
    protected abstract String getWebhookUrl();

    /**
     * 获取策略名称,默认返回类名
     * 
     * @return 策略名称
     */
    public String getStrategyName() {
        return this.getClass().getSimpleName();
    }

    /**
     * 发送消息核心方法
     * 使用HTTP工具发送JSON格式消息到飞书机器人
     * 
     * @param message 消息JSON对象
     * @return 是否发送成功
     */
    protected boolean sendMessage(JSONObject message) {
        Map<String, String> headers = new HashMap<>();
        try {
            String responseBody = HttpUtil.post(getWebhookUrl(), message.toJSONString());
            log.info("【飞书消息通知】发送飞书消息结果: {}", responseBody);
            return Objects.equals(JSON.parseObject(responseBody).get("StatusCode"), 0);
        } catch (Exception e) {
            log.error("【飞书消息通知】发送消息时发生异常: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 发送文本消息
     * 
     * @param text 消息内容
     * @return 是否发送成功
     */
    public boolean sendTextMessage(String text) {
        try {
            JSONObject message = new JSONObject();
            message.put("msg_type", "text");
            JSONObject content = new JSONObject();
            content.put("text", text);
            message.put("content", content);
            return sendMessage(message);
        } catch (Exception e) {
            log.error("【飞书消息通知】发送飞书消息失败,sendTextMessage", e);
        }
        return false;
    }

    /**
     * 发送富文本消息
     * 
     * @param title 消息标题
     * @param contentList 富文本内容列表
     * @return 是否发送成功
     */
    public boolean sendRichTextMessage(String title, List<RichTextItem> contentList) {
        try {
            JSONObject message = new JSONObject();
            message.put("msg_type", "post");
            JSONObject content = new JSONObject();
            JSONObject post = new JSONObject();
            JSONObject zhCn = new JSONObject();
            zhCn.put("title", title);
            JSONArray contentArray = new JSONArray();
            for (RichTextItem item : contentList) {
                JSONArray contentArrayItem = new JSONArray();
                JSONObject element = new JSONObject();
                element.put("tag", item.getTag());
                if ("a".equals(item.getTag())) {
                    element.put("text", item.getText());
                    element.put("href", item.getHref());
                } else {
                    element.put("text", item.getText());
                }
                if (item.getUnEscape() != null) {
                    element.put("un_escape", item.getUnEscape());
                }
                contentArrayItem.add(element);
                contentArray.add(contentArrayItem);
            }
            zhCn.put("content", contentArray);
            post.put("zh_cn", zhCn);
            content.put("post", post);
            message.put("content", content);
            log.info("【飞书消息通知】发送飞书消息结果: {}", message);
            return sendMessage(message);
        } catch (Exception e) {
            log.error("【飞书消息通知】发送飞书消息失败,sendRichTextMessage ", e);
        }
        return false;
    }

    /**
     * 发送卡片消息
     * 
     * @param params 卡片消息参数
     * @return 是否发送成功
     */
    public boolean sendCardMessage(CardMessageParams params) {
        JSONObject message = new JSONObject();
        message.put("msg_type", "interactive");

        JSONObject card = new JSONObject();
        card.put("header", createCardHeader(params.getTitle()));
        card.put("elements", createCardElements(params.getContent(), params.getButtons()));

        message.put("card", card);

        return sendMessage(message);
    }

    /**
     * 创建卡片头部
     * 
     * @param title 标题
     * @return 卡片头部对象
     */
    protected JSONObject createCardHeader(String title) {
        JSONObject header = new JSONObject();
        JSONObject titleNode = new JSONObject();
        titleNode.put("tag", "plain_text");
        titleNode.put("content", title);
        header.put("title", titleNode);
        header.put("template", "blue");
        return header;
    }

    /**
     * 创建卡片元素
     * 
     * @param content 内容
     * @param buttons 按钮列表
     * @return 卡片元素数组
     */
    protected JSONArray createCardElements(String content, List<CardButtonItem> buttons) {
        JSONArray elementsArray = new JSONArray();

        // 内容部分
        JSONObject divElement = new JSONObject();
        divElement.put("tag", "div");
        JSONObject textContent = new JSONObject();
        textContent.put("tag", "lark_md");
        textContent.put("content", content);
        divElement.put("text", textContent);
        elementsArray.add(divElement);

        // 按钮部分
        if (buttons != null && !buttons.isEmpty()) {
            JSONObject actions = new JSONObject();
            actions.put("tag", "action");
            JSONArray actionsArray = new JSONArray();

            for (CardButtonItem button : buttons) {
                JSONObject buttonNode = new JSONObject();
                buttonNode.put("tag", "button");
                JSONObject buttonText = new JSONObject();
                buttonText.put("tag", "plain_text");
                buttonText.put("content", button.getText());
                buttonNode.put("text", buttonText);
                buttonNode.put("url", button.getUrl());
                buttonNode.put("type", "primary");
                actionsArray.add(buttonNode);
            }

            actions.put("actions", actionsArray);
            elementsArray.add(actions);
        }

        return elementsArray;
    }

    /**
     * 富文本消息内容项
     */
    public static class RichTextItem {
        private String tag;
        private String text;
        private String href;
        private Boolean unEscape;
        
        public RichTextItem(String tag, String text) {
            this.tag = tag;
            this.text = text;
        }
        
        public RichTextItem(String tag, String text, String href) {
            this(tag, text);
            this.href = href;
        }
        
        public RichTextItem(String tag, String text, Boolean unEscape) {
            this(tag, text);
            this.unEscape = unEscape;
        }
        
        // getters and setters
        public String getTag() { return tag; }
        public void setTag(String tag) { this.tag = tag; }
        public String getText() { return text; }
        public void setText(String text) { this.text = text; }
        public String getHref() { return href; }
        public void setHref(String href) { this.href = href; }
        public Boolean getUnEscape() { return unEscape; }
        public void setUnEscape(Boolean unEscape) { this.unEscape = unEscape; }
    }

    /**
     * 卡片按钮项
     */
    public static class CardButtonItem {
        private String text;
        private String url;
        
        public CardButtonItem(String text, String url) {
            this.text = text;
            this.url = url;
        }
        
        // getters and setters
        public String getText() { return text; }
        public void setText(String text) { this.text = text; }
        public String getUrl() { return url; }
        public void setUrl(String url) { this.url = url; }
    }

    /**
     * 卡片消息参数类
     */
    public static class CardMessageParams {
        private String title;
        private String content;
        private List<CardButtonItem> buttons;

        public CardMessageParams() {
        }

        public CardMessageParams(String title, String content, List<CardButtonItem> buttons) {
            this.title = title;
            this.content = content;
            this.buttons = buttons;
        }

        // getters and setters
        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public String getContent() {
            return content;
        }

        public void setContent(String content) {
            this.content = content;
        }

        public List<CardButtonItem> getButtons() {
            return buttons;
        }

        public void setButtons(List<CardButtonItem> buttons) {
            this.buttons = buttons;
        }
    }
}
  1. 具体策略实现 BlogDemoMessageStrategy
java 复制代码
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 博客演示飞书消息策略实现
 * 展示如何继承抽象策略类实现具体的消息推送策略
 */
@Component
public class BlogDemoMessageStrategy extends AbstractFeishuMessageStrategy {
    // 飞书机器人webhook地址
    private static final String WEBHOOK_URL = "https://open.feishu.cn/open-apis/bot/v2/hook/7c016607-678e-4a69-9c41-e8ef0eaca031";

    /**
     * 实现获取webhook地址的方法
     * 
     * @return 飞书机器人webhook地址
     */
    @Override
    protected String getWebhookUrl() {
        return WEBHOOK_URL;
    }

    /**
     * 测试方法,演示各种消息类型的发送
     * 
     * @param args 命令行参数
     */
    public static void main(String[] args) {
        BlogDemoMessageStrategy strategy = new BlogDemoMessageStrategy();

        // 测试发送文本消息
        boolean textResult = strategy.sendTextMessage("【博客演示】这是一条来自博客演示项目的测试文本消息");
        System.out.println("文本消息发送结果: " + textResult);

        // 测试发送富文本消息
        List<RichTextItem> richContent = new ArrayList<>();
        richContent.add(new RichTextItem("text", "【技术分享】"));
        richContent.add(new RichTextItem("a", "查看完整技术文档", "https://tech-docs.example.com"));
        richContent.add(new RichTextItem("text", "\n发布时间: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())));

        boolean richResult = strategy.sendRichTextMessage("技术博客系统通知", richContent);
        System.out.println("富文本消息发送结果: " + richResult);

        // 测试发送卡片消息
        List<CardButtonItem> buttons = new ArrayList<>();
        buttons.add(new CardButtonItem("阅读更多", "https://blog.example.com/article/123"));
        buttons.add(new CardButtonItem("联系作者", "https://work.example.com/contact/author"));

        CardMessageParams cardParams = new CardMessageParams();
        cardParams.setTitle("技术博客重要提醒");
        cardParams.setContent("**文章发布状态**\n- 状态: 已发布\n- 时间: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        cardParams.setButtons(buttons);

        boolean cardResult = strategy.sendCardMessage(cardParams);
        System.out.println("卡片消息发送结果: " + cardResult);
    }
}

使用方式

通过简单的实例化和调用即可完成消息推送:

java 复制代码
// 创建策略实例
BlogDemoMessageStrategy strategy = new BlogDemoMessageStrategy();

// 发送文本消息
strategy.sendTextMessage("【博客演示】测试文本消息");

// 发送富文本消息
List<AbstractFeishuMessageStrategy.RichTextItem> richContent = new ArrayList<>();
richContent.add(new AbstractFeishuMessageStrategy.RichTextItem("text", "【系统通知】"));
boolean richResult = strategy.sendRichTextMessage("系统通知标题", richContent);

// 发送卡片消息
List<AbstractFeishuMessageStrategy.CardButtonItem> buttons = new ArrayList<>();
buttons.add(new AbstractFeishuMessageStrategy.CardButtonItem("查看详情", "https://example.com"));
CardMessageParams cardParams = new CardMessageParams();
cardParams.setTitle("重要提醒");
cardParams.setContent("这是卡片内容");
cardParams.setButtons(buttons);
strategy.sendCardMessage(cardParams);

扩展新的策略

要为新的飞书群创建消息推送策略,只需简单继承 AbstractFeishuMessageStrategy 并提供对应的 webhook 地址:

java 复制代码
@Component
public class NewTeamMessageStrategy extends AbstractFeishuMessageStrategy {
    private static final String WEBHOOK_URL = "https://open.feishu.cn/open-apis/bot/v2/hook/new-team-webhook-url";

    @Override
    protected String getWebhookUrl() {
        return WEBHOOK_URL;
    }
}

总结:

这种设计的优势在于:

1、高内聚低耦合:核心逻辑与配置分离

2、易于扩展:新增飞书群只需继承抽象类并提供 webhook URL

3、类型安全:使用专用参数类避免运行时类型错误

4、维护简便:统一的错误处理和日志记录机制

通过这套方案,开发者可以快速构建适用于不同业务场景的飞书消息推送服务。

相关推荐
科普瑞传感仪器13 分钟前
基于六维力传感器的机器人柔性装配,如何提升发动机零部件装配质量?
java·前端·人工智能·机器人·无人机
她说..13 分钟前
Java AOP完全指南:从原理到实战(全套知识点+场景总结)
java·开发语言·spring·java-ee·springboot
-大头.13 分钟前
Spring进阶:构建模块化RESTful系统全攻略
java·spring·restful
Wukong.Sun28 分钟前
【双人对战五子棋游戏】的自动化测试框架设计
java·selenium·测试工具
weixin_4365250732 分钟前
jar包启动使用logs替换nohup日志文件
java·linux·数据库
D***776534 分钟前
【Redis】在Java中以及Spring环境下操作Redis
java·redis·spring
k***z1135 分钟前
Spring boot创建时常用的依赖
java·spring boot·后端
Sally_xy35 分钟前
安装 Java
java·开发语言
第二只羽毛40 分钟前
订餐系统的代码实现
java·大数据·开发语言