【Java用法】拿来即用--使用Java开发连接钉钉H5微应用实现钉钉通知提醒的功能(方式二)

本文目录

一、项目背景

二、详细步骤

2.1 步骤一:添加依赖

2.2 步骤二、添加使用的工具类

2.3 步骤三、添加配置文件application-local.yml

2.4 步骤四、在业务中添加发送钉钉通知的代码

三、最终效果

四、拓展文件


另外实现一种方式,非常简单,代码粘下来就可以用:【Java用法】使用Java开发连接钉钉应用实现钉钉通知的功能

一、项目背景

项目架构是:Springboot (2.0.0.RELEASE) + maven (2.18.1) + mybatis-plus (3.1.1) + jdk1.8

前几天在钉钉创建了一个H5微应用,上线运行几天之后,又增加了新的需求,即当有人评论你的日报时,给你发送钉钉通知提醒一下,今天又通过另一种方式实现了钉钉通知的功能。

二、详细步骤

2.1 步骤一:添加依赖

<!-- 钉钉SDK -->
<dependency>
     <groupId>com.aliyun</groupId>
     <artifactId>alibaba-dingtalk-service-sdk</artifactId>
     <version>1.0.1</version>
</dependency>

2.2 步骤二、添加使用的工具类

参考本文拓展里的内容

2.3 步骤三、添加配置文件application-local.yml

2.4 步骤四、在业务中添加发送钉钉通知的代码

    @Override
    public JsonResult addComment(User user, DailyJobComment dailyJobComment) {

        if (user == null) {
            log.error("E|DailyCommentServiceImpl|addComment()|新增日报评论时,获取当前登录人失败!");
            return JsonResult.fail("获取当前登录人失败!");
        }

        String userName = user.getUserName();
        String trueName = user.getTrueName();
        dailyJobComment.setCreateUser(userName);
        dailyJobComment.setCreateName(trueName);
        dailyJobComment.setCreateTime(new Date());

        int insert = dailyCommentMapper.insert(dailyJobComment);
        if (insert > 0) {
            log.info("E|DailyCommentServiceImpl|addComment()|新增日报评论成功,当前登录人 trueName = {}", trueName);
            this.executeDingInform(dailyJobComment);
            return JsonResult.ok("新增日报评论成功");
        }

        return JsonResult.fail("新增日报评论失败!");
    }

    /**
     * 执行钉钉通知
     *
     * @param dailyJobComment 日报评论内容
     */
    private void executeDingInform(DailyJobComment dailyJobComment) {

        // 获取钉钉用户id
        Integer jobId = dailyJobComment.getJobId();
        DailyJob dailyJob = dailyJobMapper.selectById(jobId);
        DailyViewUser dailyViewUser = dailyViewUserMapper.getDailyViewUserByUsername(dailyJob.getCreateUser());
        String userName = dailyViewUser.getUserName();
        String dingUserId = dailyViewUser.getDingUserId();
        String createName = dailyJobComment.getCreateName();
        // 评论创建时间
        Date createTime = dailyJobComment.getCreateTime();
        ThreadUtil.excAsync(new Runnable() {
            @Override
            public void run() {
                DingTalkMsg dingTalkMsg = new DingTalkMsg();
                dingTalkMsg.setAuthor(createName + " " + DateUtil.format(createTime, "yyyy年MM月dd日 HH:mm:ss"));
                dingTalkMsg.setContent("");
                dingTalkMsg.setTitle("日报评论通知");
                dingTalkMsg.setMsgType("oa");
                dingTalkMsg.setUserList(Objects.isNull(dingUserId) ? userName : dingUserId);
                dingTalkMsg.setFromList(getFormList());
                dingTalkWorkNotice.sendDingMsg(dingTalkMsg);
            }

            private List<OapiMessageCorpconversationAsyncsendV2Request.Form> getFormList() {
                List<OapiMessageCorpconversationAsyncsendV2Request.Form> formList = DingDingMsg.create("【" + createName + "】评论了你【",
                        DateUtil.format(dailyJob.getCreateTime(), "yyyy-MM-dd HH:mm:ss") + "】创建的日报")
                        .builder("评论内容:", dailyJobComment.getContent())
                        .builder("评论时间:", DateUtil.format(createTime, "yyyy-MM-dd HH:mm:ss"))
                        .collect();

                log.info("E|DailyCommentServiceImpl|getDingInformContent()|新增日报评论成功时,封装钉钉通知内容 = {}", formList);

                return formList;
            }

        }, true);
    }

三、最终效果

实现的最终效果是,当有人评论了你的日报时,钉钉客户端就会向你推送一条消息,至于推送的内容,可以自己定制的。以下就是我本次实现的最终效果。

四、拓展文件

2.2 步骤二中使用的工具类有以下五个(DingTalkMsg.class,DingTalkParams.class,DingDingMsg.class,DingTalkUrlConstants.class,DingTalkWorkNotice.class

package com.iot.daily.dingding.domain;

import com.dingtalk.api.request.OapiMessageCorpconversationAsyncsendV2Request;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

/**
 * DingTalkMsg.java此类用于
 *
 * @author: hjm
 * @date: 2021/4/14
 * @remark:
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DingTalkMsg {

    @ApiModelProperty(value = "消息类型")
    private String msgType;

    @ApiModelProperty(value = "通知标题")
    private String title;

    @ApiModelProperty(value = "通知内容")
    private String content;

    @ApiModelProperty(value = "通知人员dingUserId列表")
    private String userList;

    @ApiModelProperty(value = "消息链接地址")
    private String url;

    @ApiModelProperty(value = "OA Form 表单内容")
    private List<OapiMessageCorpconversationAsyncsendV2Request.Form> fromList;

    @ApiModelProperty(value = "提醒人")
    private String author;
}
package com.iot.daily.dingding.domain;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

/**
 * @author openapi@dingtalk
 * @date 2020/2/4
 */
@Configuration
@Data
public class DingTalkParams {

    @Value("${dingtalk.app_key}")
    private String appKey;

    @Value("${dingtalk.app_secret}")
    private String appSecret;

    @Value("${dingtalk.agent_id}")
    private long agentId;

    @Value("${dingtalk.corp_id}")
    private String corpId;

    @Value("${dingtalk.is_open}")
    private String isOpen;
}
package com.iot.daily.dingding.util;

import com.dingtalk.api.request.OapiMessageCorpconversationAsyncsendV2Request;

import java.util.ArrayList;
import java.util.List;


/**
 * 构建钉钉发送消息
 *
 * @author hjm
 * @date 2019-04-24
 */
public class DingDingMsg {

    private List<OapiMessageCorpconversationAsyncsendV2Request.Form> mapList = new ArrayList<>();

    private DingDingMsg() {

    }

    public static DingDingMsg create(String key, String value) {
        return (new DingDingMsg()).builder(key, value);
    }

    public DingDingMsg builder(String key, String value) {

        OapiMessageCorpconversationAsyncsendV2Request.Form form = new OapiMessageCorpconversationAsyncsendV2Request.Form();
        form.setKey(key);
        form.setValue(value);
        mapList.add(form);
        return this;
    }

    public List<OapiMessageCorpconversationAsyncsendV2Request.Form> collect() {
        return this.mapList;
    }

}
package com.iot.daily.common.constant;

/**
 * <p>DingTalkUrlConstants 此类用于:调用钉钉API路径URL</p>
 * <p>@author:hjm</p>
 * <p>@date:2021年06月08日 11:20</p>
 * <p>@remark:</p>
 */
public class DingTalkUrlConstants {

    private static final String HOST = "https://oapi.dingtalk.com";

    /**
     * 钉钉网关 gettoken 地址
     */
    public static final String URL_GET_TOKEN = HOST + "/gettoken";

    /**
     * 获取 jsapi_ticket 地址
     */
    public static final String URL_GET_JSTICKET = HOST + "/get_jsapi_ticket";

    /**
     * 发送钉钉工作通知接口URL
     */
    public static final String URL_SEND_WORK_NOTICE = HOST + "/topapi/message/corpconversation/asyncsend_v2";

    /**
     * 获取用户在企业内 userId 的接口URL
     */
    public static final String URL_GET_USER_INFO = HOST + "/user/getuserinfo";

    /**
     * 获取用户姓名的接口URL
     */
    public static final String URL_USER_GET = HOST + "/user/get";

    /**
     * 获取部门列表接口URL
     */
    public static final String URL_DEPARTMENT_LIST = HOST + "/department/list";

    /**
     * 获取部门用户接口URL
     */
    public static final String URL_USER_SIMPLELIST = HOST + "/user/simplelist";
}

package com.iot.daily.dingding.util;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiGetJsapiTicketRequest;
import com.dingtalk.api.request.OapiGettokenRequest;
import com.dingtalk.api.request.OapiMessageCorpconversationAsyncsendV2Request;
import com.dingtalk.api.response.OapiGetJsapiTicketResponse;
import com.dingtalk.api.response.OapiGettokenResponse;
import com.dingtalk.api.response.OapiMessageCorpconversationAsyncsendV2Response;
import com.taobao.api.ApiException;
import com.iot.daily.common.constant.CommonConstants;
import com.iot.daily.common.constant.DingTalkUrlConstants;
import com.iot.daily.common.util.cache.RedisCache;
import com.iot.daily.dingding.domain.DingTalkMsg;
import com.iot.daily.dingding.domain.DingTalkParams;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;

/**
 * DingTalkWorkNotice.java此类用于钉钉自定义机器人
 *
 * @author:hjm
 * @date:2021年4月7日
 * @remark:
 */
@Slf4j
@Component
public class DingTalkWorkNotice {

    /**
     * 缓存时间:一小时50分钟
     */
    private static final long CACHE_TTL = 60 * 55 * 2 * 1000;

    @Resource
    private DingTalkParams dingTalkParams;

    @Resource
    private RedisCache cache;

    private final String IS_OPEN = "true";
    private final String MSG_TYPE_OA = "oa";
    private final String MSG_TYPE_LINK = "link";
    private final String MSG_TYPE_ACTION_CARD = "action_card";

    /**
     * 向钉钉发送消息
     *
     * @param dingTalkMsg 实例对象
     */
    public void sendDingMsg(DingTalkMsg dingTalkMsg) {

        String msgType = dingTalkMsg.getMsgType();
        String title = dingTalkMsg.getTitle();
        String content = dingTalkMsg.getContent();
        String userList = dingTalkMsg.getUserList();
        String url = dingTalkMsg.getUrl();
        List<OapiMessageCorpconversationAsyncsendV2Request.Form> fromList = dingTalkMsg.getFromList();
        String author = dingTalkMsg.getAuthor();

        DingTalkClient client = new DefaultDingTalkClient(DingTalkUrlConstants.URL_SEND_WORK_NOTICE);

        OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
        request.setAgentId(dingTalkParams.getAgentId());
        request.setUseridList(userList);
        request.setToAllUser(false);

        OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();

        // 消息类型
        switch (msgType) {
            case MSG_TYPE_OA:
                msg.setOa(new OapiMessageCorpconversationAsyncsendV2Request.OA());
                msg.getOa().setHead(new OapiMessageCorpconversationAsyncsendV2Request.Head());
                msg.getOa().getHead().setText("head");
                msg.getOa().setBody(new OapiMessageCorpconversationAsyncsendV2Request.Body());
                msg.getOa().getBody().setTitle(title);
                msg.getOa().getBody().setContent(content);
                msg.getOa().getBody().setForm(fromList);
                msg.getOa().getBody().setAuthor(author);

                break;
            case MSG_TYPE_LINK:
                msg.setLink(new OapiMessageCorpconversationAsyncsendV2Request.Link());
                msg.getLink().setTitle(title);
                msg.getLink().setText(content);
                msg.getLink().setMessageUrl(url);
                msg.getLink().setPicUrl("test");

                break;
            case MSG_TYPE_ACTION_CARD:
                msg.setActionCard(new OapiMessageCorpconversationAsyncsendV2Request.ActionCard());
                msg.getActionCard().setTitle(title);
                msg.getActionCard().setMarkdown(content);
                msg.getActionCard().setSingleTitle("查看详情");
                msg.getActionCard().setSingleUrl(url);

                break;
            default:
                break;
        }

        msg.setMsgtype(msgType);
        request.setMsg(msg);

        OapiMessageCorpconversationAsyncsendV2Response rsp;
        try {
            // 是否开启钉钉提醒
            if (StrUtil.equals(dingTalkParams.getIsOpen(), IS_OPEN)) {
                String accessToken = getAccessToken();
                rsp = client.execute(request, accessToken);
                log.info(rsp.getBody());
            }
        } catch (ApiException e) {
            log.error("发送钉钉工作通知异常:", e);
        }
    }

    /**
     * 在此方法中,为了避免频繁获取access_token,
     * 在距离上一次获取access_token时间在两个小时之内的情况,
     * 将直接从持久化存储中读取access_token
     * <p>
     * 因为access_token和jsapi_ticket的过期时间都是7200秒
     * 所以在获取access_token的同时也去获取了jsapi_ticket
     * 注:jsapi_ticket是在前端页面JSAPI做权限验证配置的时候需要使用的
     * 具体信息请查看开发者文档--权限验证配置
     *
     * @return accessToken 或错误信息
     */
    public String getAccessToken() throws ApiException {
        String redisKey = CommonConstants.DAILY_DING_ACCESS_TOKEN + dingTalkParams.getAppKey();

        // 从持久化存储中读取
        String accessToken = getFromCache(redisKey, "access_token");
        if (accessToken != null) {
            return accessToken;
        }

        DefaultDingTalkClient client = new DefaultDingTalkClient(DingTalkUrlConstants.URL_GET_TOKEN);
        OapiGettokenRequest request = new OapiGettokenRequest();
        OapiGettokenResponse response;

        request.setAppkey(dingTalkParams.getAppKey());
        request.setAppsecret(dingTalkParams.getAppSecret());
        request.setHttpMethod("GET");

        try {
            response = client.execute(request);
        } catch (ApiException e) {
            log.error("获取access_token失败异常:{}", e);
            throw e;
        }
        accessToken = response.getAccessToken();

        // 持久化accessToken
        putToCache(redisKey, "access_token", accessToken);

        return accessToken;
    }

    /**
     * 获取JSTicket, 用于js的签名计算
     * 正常的情况下,jsapi_ticket的有效期为7200秒,所以开发者需要在某个地方设计一个定时器,定期去更新jsapi_ticket
     *
     * @return jsTicket或错误信息
     */
    public String getJsTicket() throws ApiException {
        // 从持久化存储中读取
        String ticket = getFromCache("jsticket", "ticket");
        if (ticket != null) {
            return ticket;
        }

        String accessToken = getAccessToken();

        DefaultDingTalkClient client = new DefaultDingTalkClient(DingTalkUrlConstants.URL_GET_JSTICKET);
        OapiGetJsapiTicketRequest request = new OapiGetJsapiTicketRequest();
        OapiGetJsapiTicketResponse response;

        request.setHttpMethod("GET");

        try {
            response = client.execute(request, accessToken);
        } catch (ApiException e) {
            log.error("获取jsticket失败异常:{}", e);
            throw e;
        }

        ticket = response.getTicket();

        // 持久化jsticket
        putToCache("jsticket", "ticket", ticket);
        return ticket;
    }

    /**
     * 模拟从持久化存储中获取token并检查是否已过期
     *
     * @param section 存储key
     * @param field   token字段名
     * @return token值 或 null (过期或未查到)
     */
    private String getFromCache(String section, String field) {
        String beginTimeKey = "begin_time";
        String value = cache.get(section);
        JSONObject o = JSONObject.parseObject(value);
        if (o != null && System.currentTimeMillis() - o.getLong(beginTimeKey) <= CACHE_TTL) {
            return o.getString(field);
        }
        return null;
    }

    private void putToCache(String section, String field, String value) {
        JSONObject fieldObj = new JSONObject(2);
        fieldObj.put(field, value);
        fieldObj.put("begin_time", System.currentTimeMillis());
        cache.set(section, fieldObj.toJSONString());
    }


}

完结!

评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

No8g攻城狮

向每一个努力改变现状的你致敬!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值