前段时间做项目时遇到调用钉钉推送群消息的需求,研究钉钉开发文档和各种搜集相关内容的帖子,整理并实现推送功能,感兴趣的朋友们一起探讨一下吧。

一、准备工作

        1、在钉钉群内创建机器人,群设置->智能群助手->添加机器人->自定义;

钉钉 spring 发送图片消息 钉钉图片怎么发送_发送消息

钉钉 spring 发送图片消息 钉钉图片怎么发送_返回结果_02

钉钉 spring 发送图片消息 钉钉图片怎么发送_钉钉_03

        *填写机器人的名字,检查添加到的群组对不对,安全设置选择加签并复制密钥,程序中会用到。

钉钉 spring 发送图片消息 钉钉图片怎么发送_发送消息_04

        *获取到Webhook地址,复制下来,程序中会用到

钉钉 spring 发送图片消息 钉钉图片怎么发送_钉钉_05

 准备工作到此完成。

二、编写功能逻辑

        1.获取请求的url

/**
     * errcode处理
     *
     * @param resultStr
     */
    private static void handleErrorCode(String resultStr) {
        if (StringUtils.isEmpty(resultStr)) {
            throw new RuntimeException("返回结果为空");
        }
        JSONObject jsonObject = JSONObject.parseObject(resultStr);
        if (310000 == jsonObject.getLong("errcode")) {
            throw new RuntimeException("keywords not in content");
        }
    }

          2.报错处理 

/**
     * 获取请求url
     *
     * @return 钉钉机器人地址
     */
    private static String getDingUrl() throws Exception {
        // 获取系统时间戳
        Long timestamp = System.currentTimeMillis();
        // 拼接
        String stringToSign = timestamp + "\n" + SECRET;
        // 使用HmacSHA256算法计算签名
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(SECRET.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
        byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
        // 进行Base64 encode 得到最后的sign,可以拼接进url里
        String sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
        // 钉钉机器人地址(配置机器人的webhook),为了让每次请求不同,避免钉钉拦截,加上时间戳
        String dingUrl = WEBHOOK + "×tamp=" + timestamp + "&sign=" + sign;
        return dingUrl;
    }

        3.  发送消息

                1).发送文本类型消息

/**
     * 群里面发送消息
     *
     * @param content    消息内容
     * @param isAtAll    是否@所有人
     * @param mobileList 被@人的手机号
     * @param userIdList 被@人的用户userid
     * @throws Exception
     */
    public static void sendTextMsg(String content, List<String> mobileList, List<String> userIdList, boolean isAtAll) throws Exception {
        String dingUrl = getDingUrl();
        // 组装请求内容
        String reqStr = buildReqTextStr(content, isAtAll, mobileList, userIdList);
        // 推送消息(http请求)
        //由于用到的是公司网络需要配置代理才能连接外网,不需要代理的可以删除HttpProxy设置
        String result = HttpRequest.post(dingUrl).setHttpProxy(HOST, PORT).body(reqStr).execute().body();
        handleErrorCode(result);
        logger.info("钉钉请求发送成功,返回结果:" + result);
    }

    /**
     * 组装请求报文-text类型
     *
     * @param content    消息内容
     * @param isAtAll    是否@所有人
     * @param mobileList 被@人的手机号
     * @param atUserIds  被@人的用户userid
     * @return
     */
    public static String buildReqTextStr(String content, boolean isAtAll, List<String> mobileList, List<String> atUserIds) {
        Map<String, String> contentMap = Maps.newHashMap();
        contentMap.put("content", content);

        Map<String, Object> atMap = Maps.newHashMap();
        atMap.put("isAtAll", isAtAll);
        atMap.put("atMobiles", mobileList);
        atMap.put("atUserIds", atUserIds);

        Map<String, Object> reqMap = Maps.newHashMap();
        reqMap.put("msgtype", "text");
        reqMap.put("text", contentMap);
        reqMap.put("at", atMap);

        return JSONObject.toJSONString(reqMap);
    }

                   2).发送带有网页跳转的消息

/**
     * 群里面发送消息
     *
     * @param title      消息标题
     * @param messageUrl 点击消息跳转的URL
     * @param picUrl     图片URL
     * @param text       消息内容
     * @throws Exception
     */
    public static void sendLinkMsg(String title, String text, String messageUrl, String picUrl) throws Exception {
        String dingUrl = getDingUrl();
        // 组装请求内容
        String reqStr = buildReqLinkStr(title, text, messageUrl, picUrl);
        // 推送消息(http请求)
        //由于用到的是公司网络需要配置代理才能连接外网,不需要代理的可以删除HttpProxy设置
        String result = HttpRequest.post(dingUrl).setHttpProxy(HOST, PORT).body(reqStr).execute().body();
        handleErrorCode(result);
        logger.info("钉钉请求发送成功,返回结果:" + result);
    }

    /**
     * 组装请求报文-link类型
     *
     * @param title      消息标题
     * @param text       消息内容
     * @param messageUrl 点击消息跳转的URL
     * @param picUrl     图片URL
     * @return
     */
    private static String buildReqLinkStr(String title, String text, String messageUrl, String picUrl) {
        Map<String, String> linkMap = Maps.newHashMap();
        linkMap.put("text", text);
        linkMap.put("title", title);
        linkMap.put("picUrl", picUrl);
        linkMap.put("messageUrl", messageUrl);

        Map<String, Object> reqMap = Maps.newHashMap();
        reqMap.put("msgtype", "link");
        reqMap.put("link", linkMap);

        return JSONObject.toJSONString(reqMap);
    }

                3).发送markdown类型消息

/**
     * 群里面发送消息
     *
     * @param title      首屏会话透出的展示内容
     * @param text       markdown格式的消息
     * @param isAtAll    是否@所有人
     * @param mobileList 被@人的手机号
     * @param atUserIds  被@人的用户userid
     * @throws Exception
     */
    public static void sendMarkdownMsg(String title, String text, boolean isAtAll, List<String> mobileList, List<String> atUserIds) throws Exception {
        String dingUrl = getDingUrl();
        // 组装请求内容
        String reqStr = buildReqMarkdownStr(title, text, isAtAll, mobileList, atUserIds);
        // 推送消息(http请求)
        //由于用到的是公司网络需要配置代理才能连接外网,不需要代理的可以删除HttpProxy设置
        String result = HttpRequest.post(dingUrl).setHttpProxy(HOST, PORT).body(reqStr).execute().body();
        handleErrorCode(result);
        logger.info("钉钉请求发送成功,返回结果:" + result);
    }

    /**
     * 组装请求报文-markdown类型
     *
     * @param title      首屏会话透出的展示内容
     * @param text       markdown格式的消息
     * @param isAtAll    是否@所有人
     * @param mobileList 被@人的手机号
     * @param atUserIds  被@人的用户userid
     * @return
     */
    private static String buildReqMarkdownStr(String title, String text, boolean isAtAll, List<String> mobileList, List<String> atUserIds) {
        Map<String, String> contentMap = Maps.newHashMap();
        contentMap.put("title", title);
        contentMap.put("text", text);

        Map<String, Object> atMap = Maps.newHashMap();
        atMap.put("isAtAll", isAtAll);
        atMap.put("atMobiles", mobileList);
        atMap.put("atUserIds", atUserIds);

        Map<String, Object> reqMap = Maps.newHashMap();
        reqMap.put("msgtype", "markdown");
        reqMap.put("markdown", contentMap);
        reqMap.put("at", atMap);

        return JSONObject.toJSONString(reqMap);
    }

                4).整体跳转和独立跳转ActionCard类型

/**
     * 群里面发送消息
     *
     * @param title          首屏会话透出的展示内容
     * @param text           markdown格式的消息
     * @param btnOrientation 0:按钮竖直排列 1:按钮横向排列
     * @param singleTitle    单个按钮的标题
     * @param singleURL      点击消息跳转的URL
     * @throws Exception
     */
    public static void sendActionCardMsg(String title, String text, String btnOrientation, String singleTitle, String singleURL) throws Exception {
        String dingUrl = getDingUrl();
        // 组装请求内容
        String reqStr = buildReqActionCard(title, text, btnOrientation, singleTitle, singleURL);
        // 推送消息(http请求)
        //由于用到的是公司网络需要配置代理才能连接外网,不需要代理的可以删除HttpProxy设置
        String result = HttpRequest.post(dingUrl).setHttpProxy(HOST, PORT).body(reqStr).execute().body();
        handleErrorCode(result);
        logger.info("钉钉请求发送成功,返回结果:" + result);
    }

    /**
     * 组装请求报文-整体跳转ActionCard类型
     *
     * @param title          首屏会话透出的展示内容
     * @param text           markdown格式的消息
     * @param btnOrientation 0:按钮竖直排列 1:按钮横向排列
     * @param singleTitle    单个按钮的标题
     * @param singleURL      点击消息跳转的URL
     * @return
     */
    private static String buildReqActionCard(String title, String text, String btnOrientation, String singleTitle, String singleURL) {
        Map<String, String> actionCardMap = Maps.newHashMap();
        actionCardMap.put("title", title);
        actionCardMap.put("text", text);
        actionCardMap.put("btnOrientation", btnOrientation);
        actionCardMap.put("singleTitle", singleTitle);
        actionCardMap.put("singleURL", singleURL);

        Map<String, Object> reqMap = Maps.newHashMap();
        reqMap.put("msgtype", "actionCard");
        reqMap.put("actionCard", actionCardMap);

        return JSONObject.toJSONString(reqMap);
    }

    /**
     * 群里面发送消息
     *
     * @param title          首屏会话透出的展示内容
     * @param text           markdown格式的消息
     * @param btnOrientation 0:按钮竖直排列 1:按钮横向排列
     * @param btnsList       按钮
     * @throws Exception
     */
    public static void sendActionCardMsg(String title, String text, String btnOrientation, List<Map<String, String>> btnsList) throws Exception {
        String dingUrl = getDingUrl();
        // 组装请求内容
        String reqStr = buildReqActionCard(title, text, btnOrientation, btnsList);
        // 推送消息(http请求)
        //由于用到的是公司网络需要配置代理才能连接外网,不需要代理的可以删除HttpProxy设置
        String result = HttpRequest.post(dingUrl).setHttpProxy(HOST, PORT).body(reqStr).execute().body();
        handleErrorCode(result);
        logger.info("钉钉请求发送成功,返回结果:" + result);
    }

    /**
     * 组装请求报文-独立跳转ActionCard类型
     *
     * @param title          首屏会话透出的展示内容
     * @param text           markdown格式的消息
     * @param btnOrientation 0:按钮竖直排列 1:按钮横向排列
     * @param btnsList       按钮
     * @return
     */
    private static String buildReqActionCard(String title, String text, String btnOrientation, List<Map<String, String>> btnsList) {
        Map<String, Object> actionCardMap = Maps.newHashMap();
        actionCardMap.put("title", title);
        actionCardMap.put("text", text);
        actionCardMap.put("btnOrientation", btnOrientation);
        actionCardMap.put("btns", btnsList);

        Map<String, Object> reqMap = Maps.newHashMap();
        reqMap.put("msgtype", "actionCard");
        reqMap.put("actionCard", actionCardMap);

        return JSONObject.toJSONString(reqMap);
    }

                5). 发送freedCard类型消息

/**
     * 群里面发送消息
     *
     * @param linksList 列表集合
     * @throws Exception
     */
    public static void sendFeedCardMsg(List<Map<String, String>> linksList) throws Exception {
        String dingUrl = getDingUrl();
        // 组装请求内容
        String reqStr = buildReqFeedCard(linksList);
        // 推送消息(http请求)
        //由于用到的是公司网络需要配置代理才能连接外网,不需要代理的可以删除HttpProxy设置
        String result = HttpRequest.post(dingUrl).setHttpProxy(HOST, PORT).body(reqStr).execute().body();
        handleErrorCode(result);
        logger.info("钉钉请求发送成功,返回结果:" + result);
    }

    /**
     * 组装请求报文-FeedCard类型
     *
     * @param linksList 列表集合
     * @return
     */
    private static String buildReqFeedCard(List<Map<String, String>> linksList) {
        Map<String, Object> feedCardMap = Maps.newHashMap();
        feedCardMap.put("links", linksList);

        Map<String, Object> reqMap = Maps.newHashMap();
        reqMap.put("msgtype", "feedCard");
        reqMap.put("feedCard", feedCardMap);

        return JSONObject.toJSONString(reqMap);
    }

        以上就是整个工具类,没有太大难度,仔细看看每一块相互调用的逻辑就能掌握,此外这些消息的样式还需要自己探索,全部展示出来,就没有了探索精神