企业微信Robot(群聊机器人)消息推送Java服务

背景

需求目标

本次要做的东西需要满足如下要求

  • 方便快捷地生成对应类型的消息实体(建造者模式)
  • 提供一套Service实现,可以让各个模块快速调用并发送消息,并能够提供如下的使用模式
    • 构建服务时指定发送机器人,发送时无需关注,仅调用服务
    • 消息实体内自带Robot Key,服务根据Robot Key发送到指定机器人

OK,先简单介绍一下企业微信群聊机器人

企业微信群聊机器人

企业微信群聊机器人logo
最近发现企业微信的robot特别好用,可以用较为简便的方式推送消息,甚至可以将机器人加入不同的群聊,灵活推送各类消息。完成一些企业微信服务号完成不了的工作

微信官方文档

《如何配置群聊机器人》

简单介绍一下

直接在群聊上点击右键即可添加“群聊机器人”
添加群聊机器人
点击已添加的机器人可看到webhook地址
已添加的机器人
通过使用说明,可以推送不同种类的消息到群聊内
通过使用说明,可以推送不同种类的消息到群聊内

名词解释

  • 企业微信群聊机器人:本次需求的目标调用对象,可以在企业微信群聊中发送指定格式消息,下称Robot
  • Robot Key:企业微信机器人WebHook接口的Key参数。如https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=8606ac1f-dc01-423s3-9d74-121343ef539的Robot Key为8606ac1f-dc01-423s3-9d74-121343ef539

具体实现

类清单及功能说明

  • MessageSendService
    • 基类服务接口,定义发送服务
    • 使用泛型定义发送的消息实体,继承接口可定义具体定义实体类
  • EnterpriceWechatRobotMessageSendService
    • 企业微信Robot消息发送服务
    • 继承MessageSendService,定义消息实体类
  • EnterpriseWeChatRobotMessageSendServiceImpl
    • EnterpriceWechatRobotMessageSendService的实现类
  • EnterpriseRobotMessageDO
    • 消息实体类,用于构建Robot消息
  • ResultDTO
    • 返回结果的实体,可自行定义,不做具体赘述

MessageSendService

  • 基类服务接口,定义发送服务
  • 使用泛型定义发送的消息实体,继承接口可定义具体定义实体类
  • 使用泛型的目的:定义MessageSend系列服务,可扩展其他的消息发送方式
package demo.service.wechat.inter;

import demo.common.ResultDTO;

/**
 * MessageSendService
 * 企业微信:微信消息推送接口
 *
 * @author John Chen
 * @since 2019/12/12
 */
public interface MessageSendService<T> {
    /**
     * 推送消息
     *
     * @param msg 消息体
     * @return 返回推送结果
     */
    ResultDTO<String> sendMassage(T msg);
}

EnterpriceWechatRobotMessageSendService

  • 企业微信Robot消息发送服务
  • 继承MessageSendService,定义消息实体类
  • 没有定义新的接口方法,沿用MessageSendService内的方法作为唯一实现方法
package demo.service.wechat.inter;

import demo.model.wechat.EnterpriseRobotMessageDO;

/**
 * EnterpriceWechatRobotMessageSendService
 * 企业微信机器人消息发送接口
 *
 * @author John Chen
 * @since 2019/12/13
 */
public interface EnterpriceWechatRobotMessageSendService extends MessageSendService<EnterpriseRobotMessageDO> {
}

EnterpriseWeChatRobotMessageSendServiceImpl

  • EnterpriceWechatRobotMessageSendService的实现类
  • 说明一下其中几个自有类,可以在实际使用中删除
    • SkynetUtils:封装了公司内部日志系统日志记录功能的实现类(记录日志)
    • EnumSkynetLogModule:日志记录相关
    • EnumSkynetCategoryWechatMessageSend:日志记录相关
    • IllegalInputVariableException:自定义Exception,可以在实际使用时变更为Exception
    • OkHttp3Utils:OKHttp3封装的http服务类,用于发起http请求,可使用HTTPClient等框架代替。具体实现可参看我的另一篇原创文章《(Java)高性能Http框架:OKHttp3的工具类OkHttp3Utils实现(可使用Http代理)》
package demo.service.wechat.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import demo.common.ResultDTO;
import demo.common.enumlibrary.skynet.EnumSkynetLogModule;
import demo.common.enumlibrary.skynet.category.EnumSkynetCategoryWechatMessageSend;
import demo.common.myexception.IllegalInputVariableException;
import demo.common.utls.OkHttp3Utils;
import demo.common.utls.SkynetUtils;
import demo.model.wechat.EnterpriseRobotMessageDO;
import demo.service.wechat.inter.EnterpriceWechatRobotMessageSendService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

/**
 * EnterpriseWeChatRobotMessageSendServiceImpl
 * 企业微信机器人消息推送接口
 *
 * @author John Chen
 * @since 2019/12/12
 */
@Slf4j
public class EnterpriseWeChatRobotMessageSendServiceImpl implements EnterpriceWechatRobotMessageSendService {
    private final static String MODULE = EnumSkynetLogModule.WECHAT_MESSAGE_SEND.getName();
    private final static String CATEGORY = EnumSkynetCategoryWechatMessageSend.ENTERPRISE_ROBOT.getName();

    /**
     * 企业微信robot推送地址。在构建的时候传进来
     */
    private final String defaultPushUrl;
    /**
     * 企业微信robot推送任务名称,无实际逻辑用途,仅用于记录日志
     */
    private final String jobName;
    private final Gson gson;
    /**
     * 企业微信机器人推送地址
     */
    private final String wxEnterpriseRobotPushUrl;
    private static final String ERR_CODE_KEY = "errcode";
    private static final int ERR_CODE_SUCCESS_VALUE = 0;
    private static final String ERR_MSG_KEY = "errmsg";

    /**
     * OkHttp3实例
     */
    private OkHttp3Utils okHttp3Utils = new OkHttp3Utils();

    /**
     * 构造方法
     *
     * @param defaultPushUrl           默认消息推送地址
     * @param jobName                  名称
     * @param gson                     gson
     * @param wxEnterpriseRobotPushUrl 企业微信消息推送地址,参考地址:https://qyapi.weixin.qq.com/cgi-bin/webhook/send
     */
    public EnterpriseWeChatRobotMessageSendServiceImpl(String defaultPushUrl, String jobName, Gson gson, String wxEnterpriseRobotPushUrl) {
        this.defaultPushUrl = defaultPushUrl;
        this.jobName = jobName;
        this.gson = gson;
        this.wxEnterpriseRobotPushUrl = wxEnterpriseRobotPushUrl;
    }

    /**
     * 构造方法
     *
     * @param defaultPushUrl 默认消息推送地址
     * @param jobName        名称
     * @param gson           gson
     */
    public EnterpriseWeChatRobotMessageSendServiceImpl(String defaultPushUrl, String jobName, Gson gson) {
        this.defaultPushUrl = defaultPushUrl;
        this.jobName = jobName;
        this.gson = gson;
        this.wxEnterpriseRobotPushUrl = null;
    }

    /**
     * 推送消息
     *
     * @param msg 消息体
     * @return 返回推送结果
     */
    @Override
    public ResultDTO<String> sendMassage(EnterpriseRobotMessageDO msg) {
        try {
            String msgStr = gson.toJson(msg);
            log.info("收到企业微信推送请求,job:{};开始推送消息:{}", jobName, msgStr);
            String pushUrl = getPushUrl(msg);
            log.debug("推送地址:{}", pushUrl);
            //推送消息
            String resultStr = okHttp3Utils.post(pushUrl, msgStr);
            //记录结果并返回
            log.info("推送结果:{}", resultStr);
            JSONObject resultJson = JSONObject.parseObject(resultStr);
            boolean success = resultJson.getInteger(ERR_CODE_KEY) == ERR_CODE_SUCCESS_VALUE;
            String resMsg = resultJson.getString(ERR_MSG_KEY);
            if (!success) {
                SkynetUtils.printError(String.format("消息推送失败:%s", resMsg), MODULE, CATEGORY, "消息推送失败", jobName, "", null);
                return new ResultDTO<>(success, "发送消息成功", resultJson.getString(ERR_CODE_KEY), resMsg);
            }
            return new ResultDTO<>(success, "发送消息成功", "200", resMsg);
        } catch (Exception e) {
            String errMsg = String.format("消息推送异常:%s", e.getMessage());
            SkynetUtils.printError(errMsg, MODULE, CATEGORY, "消息推送异常", jobName, "", e);
            return new ResultDTO<>(false, "消息发送异常", "999", errMsg);
        }
    }

    /**
     * 获取推送的url地址(带key参数)
     *
     * @param msg 入参
     * @return 返回地址;如果无法组成地址,则返回null
     */
    private String getPushUrl(EnterpriseRobotMessageDO msg) {
        String key = msg.getRobotKey();
        if (!StringUtils.isEmpty(key) && !StringUtils.isEmpty(wxEnterpriseRobotPushUrl)) {
            final String urlKey = "key";
            return wxEnterpriseRobotPushUrl + "?" + urlKey + "=" + key;
        } else if (!StringUtils.isEmpty(defaultPushUrl)) {
            return defaultPushUrl;
        } else {
            throw new IllegalInputVariableException("入参中key为空或企业微信机器人推送地址为空,且任务未配置默认推送地址,无法组合出推送地址,请检查代码!");
        }

    }
}

EnterpriseRobotMessageDO

  • 消息实体类,用于构建Robot消息
  • 使用建造者模式,在具体使用过程时根据不同需求选择构建不同的Builder
package demo.model.wechat;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * EnterpriseRobotMessageDO
 * 企业微信机器人消息推送实体
 *
 * @author John Chen
 * @since 2019/12/12
 */
@ToString
public class EnterpriseRobotMessageDO {
    public final static String MSG_TYPE_TEXT = "text";
    public final static String MSG_TYPE_MARKDOWN = "markdown";
    public final static String MSG_TYPE_IMAGE = "image";
    public final static String MSG_TYPE_NEWS = "news";
    /**
     * 推送robot key(不填则由实现决定如何处理)
     * 优先使用pushKey
     */
    @Getter
    private String robotKey;
    /**
     * 消息类型枚举
     */
    private String msgtype;
    //region 不同消息类型用到的不同字段。每次仅需要实例化1个即可
    /**
     * type=text时需要去构建的实体
     */
    private TextType text;
    /**
     * type=markdown时需要去构建的实体
     */
    private MarkdownType markdown;
    /**
     * type=image时需要去构建的实体
     */
    private ImageType image;
    /**
     * type=news时需要去构建的实体
     */
    private NewsType news;
    //endregion

    /**
     * 构建一个Text类型消息实体Builder
     *
     * @param content 消息内容
     * @return 返回builder
     */
    public static TextBuilder textBuilder(String content) {
        return new TextBuilder(content);
    }

    /**
     * 构建一个Markdown类型消息实体
     *
     * @param content 消息内容(Markdown格式)
     * @return 返回builder
     */
    public static MarkdownBuilder markdownBuilder(String content) {
        return new MarkdownBuilder(content);
    }

    /**
     * 构建一个Image类型消息实体
     *
     * @param base64 图片内容的base64编码;无需增加类似data:image/png;base64,的头。这一点要注意,因为在线转换工具大多会带上这个前缀
     * @param md5    图片内容(base64编码前)的md5值;
     * @return 返回builder
     */
    public static ImageBuilder imageBuilder(String base64, String md5) {
        return new ImageBuilder(base64, md5);
    }

    /**
     * 构建一个news类型消息实体
     *
     * @param title       标题,不超过128个字节,超过会自动截断
     * @param url         点击后跳转的链接。
     * @param description 描述,不超过512个字节,超过会自动截断 非必填
     * @param picUrl      图文消息的图片链接,支持JPG、PNG格式,较好的效果为大图 1068*455,小图150*150。 非必填
     * @return 返回builder
     */
    public static NewsBuilder newsBuilder(String title, String url, String description, String picUrl) {
        return new NewsBuilder(title, url, description, picUrl);
    }

    public static NewsBuilder newsBuilder(String title, String url, String description) {
        return new NewsBuilder(title, url, description, null);
    }

    public static NewsBuilder newsBuilder(String title, String url) {
        return new NewsBuilder(title, url, null, null);
    }

    //region 消息实体类

    @AllArgsConstructor
    private static class TextType {
        /**
         * 文本内容,最长不超过2048个字节,必须是utf8编码
         */
        private String content;
        /**
         * userid的列表,提醒群中的指定成员(@某个成员),@all表示提醒所有人,如果开发者获取不到userid,可以使用mentioned_mobile_list
         */
        private List<String> mentioned_list;
        /**
         * 手机号列表,提醒手机号对应的群成员(@某个成员),@all表示提醒所有人
         */
        private List<String> mentioned_mobile_list;
    }

    @AllArgsConstructor
    private static class MarkdownType {
        /**
         * markdown内容,最长不超过4096个字节,必须是utf8编码
         */
        private String content;
    }

    @AllArgsConstructor
    private static class ImageType {
        /**
         * 图片内容的base64编码
         */
        private String base64;
        /**
         * 图片内容(base64编码前)的md5值
         */
        private String md5;
    }

    @AllArgsConstructor
    private static class NewsType {
        /**
         * 图文消息,一个图文消息支持1到8条图文
         */
        private List<Article> articles;

        /**
         * 图文消息实体
         */
        @AllArgsConstructor
        private static class Article {
            /**
             * 标题,不超过128个字节,超过会自动截断
             */
            private String title;
            /**
             * 描述,不超过512个字节,超过会自动截断
             * 非必填
             */
            private String description;
            /**
             * 点击后跳转的链接。
             */
            private String url;
            /**
             * 图文消息的图片链接,支持JPG、PNG格式,较好的效果为大图 1068*455,小图150*150。
             * 非必填
             */
            private String picurl;
        }
    }
    //endregion


    //region 各类构造方法,用于构建不同的消息类型实体

    private EnterpriseRobotMessageDO(NewsType news) {
        this.msgtype = MSG_TYPE_NEWS;
        this.news = news;
    }

    private EnterpriseRobotMessageDO(NewsType news, String robotKey) {
        this.msgtype = MSG_TYPE_NEWS;
        this.news = news;
        this.robotKey = robotKey;
    }

    private EnterpriseRobotMessageDO(ImageType image) {
        this.msgtype = MSG_TYPE_IMAGE;
        this.image = image;
    }

    private EnterpriseRobotMessageDO(ImageType image, String robotKey) {
        this.msgtype = MSG_TYPE_IMAGE;
        this.image = image;
        this.robotKey = robotKey;
    }

    private EnterpriseRobotMessageDO(MarkdownType markdown) {
        this.msgtype = MSG_TYPE_MARKDOWN;
        this.markdown = markdown;
    }

    private EnterpriseRobotMessageDO(MarkdownType markdown, String robotKey) {
        this.msgtype = MSG_TYPE_MARKDOWN;
        this.markdown = markdown;
        this.robotKey = robotKey;
    }

    private EnterpriseRobotMessageDO(TextType text) {
        this.msgtype = MSG_TYPE_TEXT;
        this.text = text;
    }

    private EnterpriseRobotMessageDO(TextType text, String robotKey) {
        this.msgtype = MSG_TYPE_TEXT;
        this.text = text;
        this.robotKey = robotKey;
    }
    //endregion

    //region 不同消息类型的Builder

    /**
     * Text类型消息Builder
     */
    public static class TextBuilder {
        /**
         * 当需要@all时候需要填入mentioned_list或mentioned_mobile_list中的
         */
        private static final String AT_ALL = "@all";
        private String content;
        private List<String> mentionedList;
        private List<String> mentionedMobileList;


        /**
         * 构造方法,消息体必填
         *
         * @param content 消息体
         */
        private TextBuilder(String content) {
            this.content = content;
        }

        /**
         * 添加userId,用于在消息中@某人
         *
         * @param mentioned 企业微信userId
         * @return 返回建造者本身
         */
        public TextBuilder addUserIdForAt(String... mentioned) {
            if (mentioned != null && mentioned.length > 0) {
                if (mentionedList == null) {
                    mentionedList = new ArrayList<>();
                }
                mentionedList.addAll(Arrays.asList(mentioned));
            }
            return this;
        }

        /**
         * 添加手机号,用于添加某人
         * 当无法获取到userId的时候,则可以添加手机号(需要是企业微信绑定的)
         *
         * @param mobiles 企业微信userId
         * @return 返回建造者本身
         */
        public TextBuilder addMobileForAt(String... mobiles) {
            if (mobiles != null && mobiles.length > 0) {
                if (mentionedMobileList == null) {
                    mentionedMobileList = new ArrayList<>();
                }
                mentionedMobileList.addAll(Arrays.asList(mobiles));
            }
            return this;
        }

        public TextBuilder atAll() {
            addMobileForAt(AT_ALL);
            return this;
        }

        public EnterpriseRobotMessageDO build() {
            return new EnterpriseRobotMessageDO(new TextType(content, mentionedList, mentionedMobileList));
        }

        public EnterpriseRobotMessageDO build(String robotKey) {
            return new EnterpriseRobotMessageDO(new TextType(content, mentionedList, mentionedMobileList), robotKey);
        }
    }

    /**
     * Markdown类型消息Builder
     */
    @AllArgsConstructor(access = AccessLevel.PRIVATE)
    public static class MarkdownBuilder {
        /**
         * markdown内容,最长不超过4096个字节,必须是utf8编码
         */
        private String content;

        public EnterpriseRobotMessageDO build() {
            return new EnterpriseRobotMessageDO(new MarkdownType(content));
        }

        public EnterpriseRobotMessageDO build(String robotKey) {
            return new EnterpriseRobotMessageDO(new MarkdownType(content), robotKey);
        }

    }

    /**
     * Image类型消息Builder
     */
    @AllArgsConstructor(access = AccessLevel.PRIVATE)
    public static class ImageBuilder {
        /**
         * 图片内容的base64编码
         */
        private String base64;
        /**
         * 图片内容(base64编码前)的md5值
         */
        private String md5;

        public EnterpriseRobotMessageDO build() {
            return new EnterpriseRobotMessageDO(new ImageType(base64, md5));
        }

        public EnterpriseRobotMessageDO build(String robotKey) {
            return new EnterpriseRobotMessageDO(new ImageType(base64, md5), robotKey);
        }
    }

    /**
     * News类型消息Builder
     */
    public static class NewsBuilder {
        /**
         * 图文消息,一个图文消息支持1到8条图文
         */
        private List<NewsType.Article> articles;

        /**
         * 构造方法
         *
         * @param title       标题
         * @param url         跳转地址
         * @param description 描述(非必填)
         * @param picUrl      图片地址(非必填)
         */
        private NewsBuilder(String title, String url, String description, String picUrl) {
            this.articles = new ArrayList<>(Collections.singletonList(new NewsType.Article(title, description, url, picUrl)));
        }

        /**
         * 新增一个图文
         *
         * @param title       标题
         * @param url         跳转地址
         * @param description 描述(可为空)
         * @param picUrl      图片地址
         * @return 返回builder
         */
        public NewsBuilder addArticles(String title, String url, String description, String picUrl) {
            articles.add(new NewsType.Article(title, description, url, picUrl));
            return this;
        }

        /**
         * 新增一个图文
         *
         * @param title       标题
         * @param url         跳转地址
         * @param description 描述(可为空)
         * @return 返回builder
         */
        public NewsBuilder addArticles(String title, String url, String description) {
            return addArticles(title, url, description, null);
        }

        /**
         * 新增一个图文
         *
         * @param title 标题
         * @param url   跳转地址
         * @return 返回builder
         */
        public NewsBuilder addArticles(String title, String url) {
            return addArticles(title, url, null, null);
        }

        public EnterpriseRobotMessageDO build() {
            return new EnterpriseRobotMessageDO(new NewsType(articles));
        }

        public EnterpriseRobotMessageDO build(String robotKey) {
            return new EnterpriseRobotMessageDO(new NewsType(articles), robotKey);
        }
    }
    //endregion
}

测试Demo(使用方式)

这里通过几个测试Demo来说明一下使用方法

服务Bean构建

  • 下面的案例使用了Spring框架先构建了一个Bean
  • 也可以不通过Spring框架,直接new一个实现
package demo.nelsen.config;

import com.google.gson.Gson;
import demo.common.enumlibrary.tccomponent.EnumAirtravelOpsMonitorDataNelsenKeys;
import demo.service.wechat.impl.EnterpriseWeChatRobotMessageSendServiceImpl;
import demo.service.wechat.inter.EnterpriceWechatRobotMessageSendService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * WechatSendMessageConfig
 * 企业微信消息推送Bean
 *
 * @author John Chen
 * @since 2019/12/13
 */
@Configuration
public class WechatSendMessageConfig {

    /**
     * 企业微信机器人公共推送服务
     * 注意:使用这个Bean的时候,在发送时需要带上对应的机器人Key,否则会导致发送到默认机器人上
     *
     * @param gson gson
     * @return 返回bean
     * @throws Exception 获取统一配置时可能出现的错误
     */
    @Bean
    public EnterpriceWechatRobotMessageSendService publicWxRobotSendService(Gson gson) throws Exception {
        return new EnterpriseWeChatRobotMessageSendServiceImpl("https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=8606ac1f-dc01-423s3-9d74-121343ef539", "企业微信Robot公共推送服务", gson, "https://qyapi.weixin.qq.com/cgi-bin/webhook/send");
    }
}

测试用例

下面的测试用例分别构建了4中不同的消息类型进行推送

  • 如果不想使用Spring框架,可以直接new一个EnterpriceWechatRobotMessageSendService
package demo.nelsen.tests;

import demo.common.utls.EncodeUtils;
import demo.model.wechat.EnterpriseRobotMessageDO;
import demo.service.wechat.inter.EnterpriceWechatRobotMessageSendService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;

/**
 * WechatSendMessageConfig
 * 微信发送消息测试用例集
 *
 * @author John Chen
 * @since 2019/12/13
 */
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class WechatSendMessageTests {
    @Autowired
    private EnterpriceWechatRobotMessageSendService publicWxRobotSendService;

    @Test
    public void tiantiUploadSendTest() {
        /*
        文本消息类型
         */
        EnterpriseRobotMessageDO messageTextDO = EnterpriseRobotMessageDO.textBuilder("nelsen测试用例中-上传动态-测试用例-test消息").addMobileForAt("13800000000").build();
        assert tianTiUploadRobotSendService.sendMassage(messageTextDO).getSuccess();
        /*
        markdown类型消息
         */
        EnterpriseRobotMessageDO messageMarkdownDo = EnterpriseRobotMessageDO.markdownBuilder(
                "# 消息发送测试\n" +
                        ">小鲜肉<font color=\"info\">最牛</font>\n" +
                        ">消息来自<font color=\"comment\">上传动态-Markdown类型消息</font>").build();
        assert tianTiUploadRobotSendService.sendMassage(messageMarkdownDo).getSuccess();
        /*
        图片类型
         */
        String imageB = "data:image/gif;base64,R0lGODlhdQAmAKIAAOYyL+rU4llg6Jmd8e92dCky4eEGAv///yH5BAAAAAAALAAAAAB1ACYAAAP/eLrc/jC2IEoZMATJu/9gyFVWIUyksIls677LUJbrEcxWDe98f+CWk4I0w/iOSNANKJQBC8mo9LEEDp8F3XR7rOIU2Cx3jHwKsUKyWqRhEEvGN3xN91BoCq8l9tTW/244Rk4mOkBGgIl8VjF+d4V5A5KKf3IWiCCEOZRraGxPnGqeIZpzoVyjDBptDpYmp1yumI9BWq5QUQS6fn+lm3lYmLdSBsW8xcjJBgAABLwfAMhXRQt6ODWuJ8rb3AYK0d3h4OHIBC7jC0TCYb/ZB+Th3/Dc4/PmLOgSvkwK+xjMAAEmCwhQnrc8rFSxGkiwnoFnEnTp0mdqlJw0DgIggwgu/08xABM+KkhGJdm9JJqMhGkyQIAATA3HxVwATuO8jyQfECiXJyYzZwzyOSilcqWEmzkP1ES6LGmDcStshjspNJAgMOwwNmBajGZXGyJVhU22quxOaR7hrahqQ52DC1jh/nj1AG0Eux3BLgu59x3SkxHO9mVLhJfcirUc2IWA96vUbvf+QkNbldCgIGCKHi6h1e/Bu1+VOiYHYAVTwBHyCfWyocoZzZovbf3ok1njzx/IltUg+GG13twMfta0gdDruLH3MOD6uaPDcI8hCAZp4/k24elmtOacGXlcPAuYe/VmnVt0ncioTyeYU+ibQRWOHyCRXEz40BDyivYWYBzQAIbTbeBUNTIZRF1QlNlVimGdfffLSPg9oJ9+vVV4H23smWSgFqrZZc0AWiTWACMXcjAhfgAqgxpXKwDXDXbZsSPjVcth6NNtZj3nzCpM1dDfPDACM+OQ9l2I1HiPlfNceentMoGLygQp5Eq3aKfYaUgOdBIB9RyYSEsmvASiFgG0RMRLEK2RAAA7";

        EnterpriseRobotMessageDO messageImageDo = EnterpriseRobotMessageDO.imageBuilder(
                imageB
                , EncodeUtils.md5bytes(EncodeUtils.decodeBase64(imageB))
        ).build();
        assert tianTiUploadRobotSendService.sendMassage(messageImageDo).getSuccess();
        /*
        图文消息类型
         */
        EnterpriseRobotMessageDO messageNewsDO = EnterpriseRobotMessageDO.newsBuilder("上传动态-news类型消息-跳转"
                , "https://www.baidu.com/"
                , "上传动态-news类型消息-测试用例1"
                , "http://img1.imgtn.bdimg.com/it/u=3334640638,1744228669&fm=26&gp=0.jpg")
                .addArticles("上传动态-news类型消息-跳转TCSchedule"
                        , "https://www.baidu.com/"
                        , "上传动态-news类型消息-测试用例2"
                        , "http://img1.imgtn.bdimg.com/it/u=3334640638,1744228669&fm=26&gp=0.jpg")
                .build();
        assert tianTiUploadRobotSendService.sendMassage(messageNewsDO).getSuccess();


    }
}

发布了7 篇原创文章 · 获赞 12 · 访问量 2287

猜你喜欢

转载自blog.csdn.net/weixin_42182797/article/details/105585852
今日推荐