目录
1.说明
在钉钉开放文档中可以查看有关日志相关的api,主要用到以下几个api:
①获取模板详情
②获取用户发送日志的概要信息
③获取日志接收人员列表
④创建日志
发送日志时需要根据模板规定日志的格式,所以先获取要发送日志的模板信息,然后获取用户在最近一段时间内发送的日志的概要信息,并根据最新一次的日志信息获取日志的接收人员信息,然后调用创建日志的api,设置日志内容,及接收人员。
2.示例
依赖
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>alibaba-dingtalk-service-sdk</artifactId>
<version>2.0.0</version>
</dependency>
钉钉工具类
package com.kingagroot.info.common.tools.common;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.*;
import com.dingtalk.api.response.*;
import com.kingagroot.info.common.contants.CommonContants;
import com.kingagroot.info.common.tools.thirdparty.DingDingTool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
/**
* @Author linaibo
* @Date 2024/1/6 16:18
* @Version 1.0
*/
@Component
public class DingTool {
private static LogTool logTool;
@Autowired
public void setLogTool(LogTool logTool) {
DingTool.logTool = logTool;
}
// 权限用户名
private static String accessKey;
// 权限密码
private static String secret;
// agent_id
private static Long agentId;
// tokenUrl
private static String tokenUrl;
// 发送消息url
private static String sendMsgUrl;
// 系统url
private static String sysUrl;
// 模板名称
private static String dingTemplateName;
// 模板url
private static String dingTemplateUrl;
// 创建日报url
private static String dingCreateUrl;
// 日志信息url
private static String simpleListUrl;
// 接收人信息url
private static String receiverUrl;
@NacosValue(value = "${dingding.appkey}", autoRefreshed = true)
public void setAccessKey(String accessKey) {
DingTool.accessKey = accessKey;
}
@NacosValue(value = "${dingding.appsecret}", autoRefreshed = true)
public void setSecret(String secret) {
DingTool.secret = secret;
}
@NacosValue(value = "${dingding.agentId}", autoRefreshed = true)
public void setAgentId(Long agentId) {
DingTool.agentId = agentId;
}
@NacosValue(value = "${dingding.gettoken}", autoRefreshed = true)
public void setTokenUrl(String tokenUrl) {
DingTool.tokenUrl = tokenUrl;
}
@NacosValue(value = "${dingding.sendMsg}", autoRefreshed = true)
public void setSendMsgUrl(String sendMsgUrl) {
DingTool.sendMsgUrl = sendMsgUrl;
}
@NacosValue(value = "${sys.url}", autoRefreshed = true)
public void setSysUrl(String sysUrl) {
DingTool.sysUrl = sysUrl;
}
@NacosValue(value = "${dingding.templateName}", autoRefreshed = true)
public void setDingTemplateName(String dingTemplateName) {
DingTool.dingTemplateName = dingTemplateName;
}
@NacosValue(value = "${dingding.templateUrl}", autoRefreshed = true)
public void setDingTemplateUrl(String dingTemplateUrl) {
DingTool.dingTemplateUrl = dingTemplateUrl;
}
@NacosValue(value = "${dingding.createUrl}", autoRefreshed = true)
public void setDingCreateUrl(String dingCreateUrl) {
DingTool.dingCreateUrl = dingCreateUrl;
}
@NacosValue(value = "${dingding.simpleListUrl}", autoRefreshed = true)
public void setSimpleListUrl(String simpleListUrl) {
DingTool.simpleListUrl = simpleListUrl;
}
@NacosValue(value = "${dingding.receiverUrl}", autoRefreshed = true)
public void setReceiverUrl(String receiverUrl) {
DingTool.receiverUrl = receiverUrl;
}
/**
* 获取钉钉token
*
* @return
*/
public static String getDingToken() {
DingTalkClient client = new DefaultDingTalkClient(tokenUrl);
OapiGettokenRequest request = new OapiGettokenRequest();
request.setAppkey(accessKey);
request.setAppsecret(secret);
request.setHttpMethod("GET");
try {
OapiGettokenResponse response = client.execute(request);
if (response.isSuccess()) {
// 调用成功返回token信息
return response.getAccessToken();
}
// 调用接口异常,输出异常信息,发送钉钉通知
processErrMsg("getDingToken", "获取钉钉token失败", JSON.toJSONString(response));
} catch (Exception e) {
// 调用接口异常,输出异常信息
processErrMsg("getDingToken", "获取钉钉token失败", JSON.toJSONString(e));
}
return null;
}
public static void processErrMsg(String method, String errorMsg, String responseMsg, String... dingId) {
StringBuilder errMsg = new StringBuilder();
errMsg.append(errorMsg).append(",响应信息:").append(JSON.toJSONString(responseMsg));
if (dingId.length != CommonContants.NUM_0) {
errMsg.append(",钉钉id:").append(dingId[0]);
}
logTool.saveExceptionLog("", "DingTool", method, errMsg.toString());
DingDingTool.sendDingMsg(errMsg.toString());
}
/**
* 发送钉钉通知
*
* @param token
* @param pwd
* @param userCode
*/
public static boolean sendMsg(String token, String pwd, String userCode) {
DingTalkClient client = new DefaultDingTalkClient(sendMsgUrl);
OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
request.setAgentId(agentId);
request.setUseridList(userCode);
request.setToAllUser(false);
OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
msg.setMsgtype("text");
msg.setText(new OapiMessageCorpconversationAsyncsendV2Request.Text());
StringBuilder content = new StringBuilder();
content.append("系统地址: ");
content.append(sysUrl);
content.append(" ");
content.append("密码: ");
content.append(pwd);
msg.getText().setContent(content.toString());
request.setMsg(msg);
try {
OapiMessageCorpconversationAsyncsendV2Response result = client.execute(request, token);
if (result.isSuccess()) {
return true;
}
// 调用接口异常,输出异常信息
processErrMsg("sendMsg", "发送钉钉消息(密码)失败", JSON.toJSONString(result));
} catch (Exception e) {
// 调用接口异常,输出异常信息
processErrMsg("sendMsg", "发送钉钉消息(密码)失败", JSON.toJSONString(e));
}
return false;
}
/**
* 发送钉钉通知
*
* @param token
* @param message
* @param dingId
*/
public static void sendMessage(String token, String message, String dingId) {
DingTalkClient client = new DefaultDingTalkClient(sendMsgUrl);
OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
request.setAgentId(agentId);
// 设置接收者列表
request.setUseridList(dingId);
// 是否发送给公司全员
request.setToAllUser(false);
// 设置发送的消息类型及消息内容
OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
msg.setMsgtype(CommonContants.TEXT);
msg.setText(new OapiMessageCorpconversationAsyncsendV2Request.Text());
msg.getText().setContent(message);
request.setMsg(msg);
try {
OapiMessageCorpconversationAsyncsendV2Response result = client.execute(request, token);
if (result.isSuccess()) {
return;
}
// 调用接口异常,输出异常信息
processErrMsg("sendMessage", "发送钉钉消息失败", JSON.toJSONString(result));
} catch (Exception e) {
// 调用接口异常,输出异常信息
processErrMsg("sendMessage", "发送钉钉消息失败", JSON.toJSONString(e));
}
}
/**
* 查询钉钉模板信息
*
* @param token
* @param dingId
*/
public static OapiReportTemplateGetbynameResponse.ReportTemplateResponseVo getTemplate(String token, String dingId) {
DingTalkClient client = new DefaultDingTalkClient(dingTemplateUrl);
OapiReportTemplateGetbynameRequest req = new OapiReportTemplateGetbynameRequest();
req.setUserid(dingId);
req.setTemplateName(dingTemplateName);
try {
OapiReportTemplateGetbynameResponse rsp = client.execute(req, token);
if (rsp.isSuccess()) {
// 日志内容的校验
if (CollUtil.isEmpty(rsp.getResult().getFields()) ||
!Objects.equals(rsp.getResult().getFields().get(0).getType(), CommonContants.LONG_1)) {
processErrMsg("getTemplate", "模板内容已经修改", JSON.toJSONString(rsp.getResult()), dingId);
sendMessage(token, "模板内容已经修改,系统无法进行日志推送,请自行发送。" + DateUtil.formatDateTime(new Date()), dingId);
return null;
}
return rsp.getResult();
}
// 调用接口异常,输出异常信息,发送钉钉通知
processErrMsg("getTemplate", "获取作物育种信息模板失败", JSON.toJSONString(rsp), dingId);
sendMessage(token, "获取作物育种信息模板失败,系统无法进行日志推送,请自行发送。" + DateUtil.formatDateTime(new Date()), dingId);
} catch (Exception e) {
// 调用接口异常,输出异常信息,发送钉钉通知
processErrMsg("getTemplate", "获取作物育种信息模板失败", JSON.toJSONString(e), dingId);
sendMessage(token, "获取作物育种信息模板失败,系统无法进行日志推送,请自行发送。" + DateUtil.formatDateTime(new Date()), dingId);
}
return null;
}
/**
* 获取用户在某个时间段的日志信息
*
* @param dingId
* @param token
* @return
*/
public static OapiReportSimplelistResponse.ReportOapiVo getSimpleReport(String token, String dingId) {
DingTalkClient client = new DefaultDingTalkClient(simpleListUrl);
OapiReportSimplelistRequest req = new OapiReportSimplelistRequest();
long endTime = System.currentTimeMillis();
long startTime = Instant.now().minus(CommonContants.LONG_21, ChronoUnit.DAYS).toEpochMilli();
req.setStartTime(startTime);
req.setEndTime(endTime);
req.setTemplateName(dingTemplateName);
req.setUserid(dingId);
req.setCursor(CommonContants.LONG_0);
req.setSize(CommonContants.LONG_20);
try {
OapiReportSimplelistResponse rsp = client.execute(req, token);
if (rsp.isSuccess()) {
List<OapiReportSimplelistResponse.ReportOapiVo> dataList = rsp.getResult().getDataList();
if (CollUtil.isEmpty(dataList)) {
DingDingTool.sendDingMsg("获取最近的日志信息为空,钉钉id:" + dingId);
sendMessage(token, "获取最近的日志信息为空,系统无法进行日志推送,请自行发送。" + DateUtil.formatDateTime(new Date()), dingId);
return null;
} else {
// 获取最新一次的日报信息
Optional<OapiReportSimplelistResponse.ReportOapiVo> lastReport = dataList.stream()
.max(Comparator.comparingLong(OapiReportSimplelistResponse.ReportOapiVo::getCreateTime));
return lastReport.get();
}
}
processErrMsg("getSimpleReport", "获取最近的日志信息失败", JSON.toJSONString(rsp), dingId);
sendMessage(token, "获取最近的日志信息失败,系统无法进行日志推送,请自行发送。" + DateUtil.formatDateTime(new Date()), dingId);
} catch (Exception e) {
processErrMsg("getSimpleReport", "获取最近的日志信息失败", JSON.toJSONString(e), dingId);
sendMessage(token, "获取最近的日志信息失败,系统无法进行日志推送,请自行发送。" + DateUtil.formatDateTime(new Date()), dingId);
}
return null;
}
public static List<String> getReceiver(OapiReportSimplelistResponse.ReportOapiVo report, String token) {
DingTalkClient client = new DefaultDingTalkClient(receiverUrl);
OapiReportReceiverListRequest req = new OapiReportReceiverListRequest();
req.setReportId(report.getReportId());
try {
OapiReportReceiverListResponse rsp = client.execute(req, token);
if (rsp.isSuccess()) {
List<String> useridList = rsp.getResult().getUseridList();
if (CollUtil.isEmpty(useridList)) {
DingDingTool.sendDingMsg("查询的日志接收人信息为空,请求信息:" + JSON.toJSONString(report));
sendMessage(token, "查询的日志接收人信息为空,系统无法进行日志推送,请自行发送。" + DateUtil.formatDateTime(new Date()), report.getCreatorId());
return null;
}
return useridList;
}
processErrMsg("getReceiver", "查询日志的接收人信息失败", JSON.toJSONString(rsp), report.getCreatorId());
sendMessage(token, "查询日志的接收人信息失败,系统无法进行日志推送,请自行发送。" + DateUtil.formatDateTime(new Date()), report.getCreatorId());
} catch (Exception e) {
processErrMsg("getReceiver", "查询日志的接收人信息失败", JSON.toJSONString(e), report.getCreatorId());
sendMessage(token, "查询日志的接收人信息失败,系统无法进行日志推送,请自行发送。" + DateUtil.formatDateTime(new Date()), report.getCreatorId());
}
return null;
}
/**
* 发送钉钉日报
*
* @param createDataParam
* @param token
*/
public static void createReport(OapiReportCreateRequest.OapiCreateReportParam createDataParam, String token) {
DingTalkClient client = new DefaultDingTalkClient(dingCreateUrl);
OapiReportCreateRequest req = new OapiReportCreateRequest();
req.setCreateReportParam(createDataParam);
try {
OapiReportCreateResponse rsp = client.execute(req, token);
if (!rsp.isSuccess()) {
// 调用接口异常,输出异常信息
processErrMsg("createReport", "发送日报失败", JSON.toJSONString(rsp), JSON.toJSONString(createDataParam));
sendMessage(token, "系统发送日志失败,请自行发送。" + DateUtil.formatDateTime(new Date()), createDataParam.getUserid());
}
} catch (Exception e) {
// 调用接口异常,输出异常信息
processErrMsg("createReport", "发送日报失败", JSON.toJSONString(e), JSON.toJSONString(createDataParam));
sendMessage(token, "系统发送日志失败,请自行发送。" + DateUtil.formatDateTime(new Date()), createDataParam.getUserid());
}
}
}
发送钉钉日报
/**
* 发送钉钉日报
*
* @param farmWorkMap
*/
private void processDingTalkReports(Map<String, List<FarmInfoDto>> farmWorkMap) {
// 钉钉id为空的用户列表,此类用户没有加入钉钉组织
StringBuilder errUserId = new StringBuilder();
// 循环农事信息列表,进行如下处理
for (Map.Entry<String, List<FarmInfoDto>> farm : farmWorkMap.entrySet()) {
// 用户及钉钉id
String userId = farm.getKey();
String dingId = farm.getValue().get(0).getDingId();
// 钉钉id为空时,无法进行发送处理
if (StrUtil.isBlank(dingId)) {
errUserId.append(userId).append(",");
continue;
}
// 获取钉钉的token信息
String dingToken = getDingToken();
if (StrUtil.isBlank(dingToken)) {
continue;
}
// 获取模板信息
OapiReportTemplateGetbynameResponse.ReportTemplateResponseVo template =
DingTool.getTemplate(dingToken, dingId);
if (ObjectUtil.isNull(template)) {
continue;
}
// 获取接收人信息
OapiReportSimplelistResponse.ReportOapiVo simpleReport = DingTool.getSimpleReport(dingToken, dingId);
List<String> receiver = new ArrayList<>();
if (ObjectUtil.isNotNull(simpleReport)) {
receiver = DingTool.getReceiver(simpleReport, dingToken);
}
if (CollUtil.isNotEmpty(receiver)) {
// 构建发送日报的请求信息
OapiReportCreateRequest.OapiCreateReportParam createDataParam = getCreateDataParam(template, farm, receiver);
// 发送钉钉日报
DingTool.createReport(createDataParam, dingToken);
}
}
// 如果有问题的用户列表不为空,则将有问题的用户列表推送至钉钉群中
if (StrUtil.isNotEmpty(errUserId)) {
DingDingTool.sendDingMsg("以下用户不存在钉钉id,用户:" + errUserId);
}
}
// 获取钉钉token
public String getDingToken() {
String dingDingToken = RedisTool.getString(redisEntr.getJedis(), CommonContants.DINGDING_TOKEN);
if (StrUtil.isEmpty(dingDingToken)) {
// 获取token
dingDingToken = DingTool.getDingToken();
// 存储token
RedisTool.setString(redisEntr.getJedis(), CommonContants.DINGDING_TOKEN, dingDingToken, 5400);
}
return dingDingToken;
}
/**
* 获取创建日报的请求信息
*
* @param template
* @param farmMap
*/
public OapiReportCreateRequest.OapiCreateReportParam getCreateDataParam(OapiReportTemplateGetbynameResponse.ReportTemplateResponseVo template,
Map.Entry<String, List<FarmInfoDto>> farmMap,
List<String> receivers) {
// 获取模板内容信息
List<OapiReportTemplateGetbynameResponse.Fields> fields = template.getFields();
// 构建创建日报请求结构
OapiReportCreateRequest.OapiCreateReportParam createReportParam = new OapiReportCreateRequest.OapiCreateReportParam();
List<OapiReportCreateRequest.OapiReportContentVo> list = new ArrayList<>();
OapiReportCreateRequest.OapiReportContentVo obj = new OapiReportCreateRequest.OapiReportContentVo();
list.add(obj);
// 添加日报内容,只添加模板的第一项
OapiReportTemplateGetbynameResponse.Fields field = fields.get(0);
obj.setSort(field.getSort());
obj.setType(field.getType());
obj.setContentType(CommonContants.MARKDOWN);
StringBuilder farmInfo = new StringBuilder();
for (int i = 0; i < farmMap.getValue().size(); i++) {
FarmInfoDto farm = farmMap.getValue().get(i);
farmInfo.append(i + 1).append(". ").append(farm.getBsName()).append(" ").append(farm.getFarmName()).append(" ");
if (farm.getWorkCount().compareTo(BigDecimal.ZERO) > CommonContants.NUM_0) {
farmInfo.append(farm.getWorkCount().stripTrailingZeros().toPlainString()).append(farm.getWorkValue()).append(" ");
}
if (StrUtil.isNotBlank(farm.getParticipants())) {
farmInfo.append("参与人:").append(farm.getParticipants());
}
farmInfo.append("\n");
}
obj.setContent(farmInfo.toString());
obj.setKey(field.getFieldName());
createReportParam.setContents(list);
// 设置汇报人信息
createReportParam.setToUserids(receivers);
// 设置模板id
createReportParam.setTemplateId(template.getId());
// 是否发送单聊消息
createReportParam.setToChat(false);
// 日志来源
createReportParam.setDdFrom(CommonContants.TJNS);
// 创建日志的用户id
createReportParam.setUserid(template.getUserid());
return createReportParam;
}
3.总结
①我使用的是企业内部创建应用的方式,创建应用后可以拿到应用的凭证信息。
②要调用日志相关的接口,需要开通日志接口的权限信息,如下:
③测试时,可以创建一个企业账号,然后创建应用,并开通日志相关接口的权限,拉入相关人员,设置日志模板,并设置人员的上下级关系进行测试。