| | |
| | | import com.gs.xky.mapper.MesStaffMapper; |
| | | import com.gs.xky.service.DingtalkInfoService; |
| | | import com.gs.xky.service.SimpleExample; |
| | | import com.taobao.api.FileItem; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.util.StringUtils; |
| | | |
| | | import java.io.File; |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public boolean sendActionCardMessage() { |
| | | try { |
| | | // 1. 获取需要推送的用户列表(可以是固定推送用户) |
| | | List<DingtalkInfo> fixedList = baseMapper.selectList( |
| | | new LambdaQueryWrapper<DingtalkInfo>().eq(DingtalkInfo::getIsHead, 1) |
| | | ); |
| | | |
| | | List<Long> sidList = fixedList.stream() |
| | | .map(DingtalkInfo::getSid) |
| | | .collect(Collectors.toList()); |
| | | |
| | | List<String> userIdList = getDingtalkUserIdListBySids(sidList); |
| | | |
| | | if (userIdList == null || userIdList.isEmpty()) { |
| | | log.warn("没有需要发送钉钉消息的用户"); |
| | | return false; |
| | | } |
| | | |
| | | String userIdListStr = String.join(",", userIdList); |
| | | |
| | | // 2. 构建消息内容 |
| | | String title = "生产数据看板"; |
| | | String markdown = "请点击下方按钮查看详细BI报表"; |
| | | String singleTitle = "查看报表"; |
| | | String singleUrl = "http://192.168.1.22:8081/design?fid=rpte6045ab079b211f0824bd3cfd50c6b93&fserid=4b198960bedd11f09f6f792bfe147b64&fsharetype=3"; |
| | | |
| | | // 3. 发送消息 |
| | | OapiMessageCorpconversationAsyncsendV2Response rsp = |
| | | sendActionCardMessage(userIdListStr, title, markdown, singleTitle, singleUrl); |
| | | |
| | | log.info("成功发送ActionCard消息: {}", rsp.getBody()); |
| | | return true; |
| | | } catch (Exception e) { |
| | | log.error("发送ActionCard消息失败", e); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public boolean sendFileMessage(String filePath) throws Exception { |
| | | try { |
| | | // 1. 检查文件是否存在 |
| | | File file = new File(filePath); |
| | | if (!file.exists()) { |
| | | log.error("文件不存在: {}", filePath); |
| | | return false; |
| | | } |
| | | |
| | | // 2. 获取需要推送的用户列表(可根据实际需求调整,这里使用isHead=1的用户) |
| | | List<DingtalkInfo> fixedList = baseMapper.selectList( |
| | | new LambdaQueryWrapper<DingtalkInfo>().eq(DingtalkInfo::getIsHead, 1) |
| | | ); |
| | | |
| | | if (fixedList == null || fixedList.isEmpty()) { |
| | | log.warn("没有需要发送文件的用户(isHead=1)"); |
| | | return false; |
| | | } |
| | | |
| | | List<String> sidList = fixedList.stream() |
| | | .map(DingtalkInfo::getPhone) |
| | | .collect(Collectors.toList()); |
| | | |
| | | List<String> userIdList = getDingtalkUserIdListByPhones(sidList); |
| | | |
| | | if (userIdList == null || userIdList.isEmpty()) { |
| | | log.warn("没有有效的钉钉用户ID"); |
| | | return false; |
| | | } |
| | | |
| | | String userIdListStr = String.join(",", userIdList); |
| | | |
| | | // 3. 上传文件到钉钉服务器 |
| | | log.info("开始上传文件: {}", filePath); |
| | | String mediaId = uploadMedia(filePath, "file"); |
| | | |
| | | // 4. 发送文件消息 |
| | | log.info("开始发送文件消息,mediaId: {}", mediaId); |
| | | OapiMessageCorpconversationAsyncsendV2Response response = sendFileMessageByMediaId(userIdListStr, mediaId); |
| | | |
| | | log.info("文件消息发送响应: {}", response.getBody()); |
| | | return response.getErrcode() == 0; |
| | | |
| | | } catch (Exception e) { |
| | | log.error("发送文件消息失败", e); |
| | | throw e; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 根据指定的sid列表获取钉钉用户ID列表 |
| | | * |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | private List<String> getDingtalkUserIdListByPhones(List<String> phoneList) { |
| | | try { |
| | | if (phoneList == null || phoneList.isEmpty()) { |
| | | return new ArrayList<>(); |
| | | } |
| | | |
| | | // 去重 |
| | | phoneList = phoneList.stream().distinct().collect(Collectors.toList()); |
| | | |
| | | // 根据sid查询DingtalkInfo |
| | | List<DingtalkInfo> list = baseMapper.selectList( |
| | | new LambdaQueryWrapper<DingtalkInfo>().in(DingtalkInfo::getPhone, phoneList) |
| | | ); |
| | | |
| | | if (list == null || list.isEmpty()) { |
| | | return new ArrayList<>(); |
| | | } |
| | | |
| | | // 使用stream流过滤出list中dingtalkId为空的数据 |
| | | List<DingtalkInfo> emptyDingtalkIdList = list.stream() |
| | | .filter(info -> !StringUtils.hasText(info.getDingtalkId())) |
| | | .collect(Collectors.toList()); |
| | | |
| | | // 如果存在为空的数据就通过钉钉的接口获取,为dingtalkId赋值,并且更新数据库 |
| | | if (!emptyDingtalkIdList.isEmpty()) { |
| | | String accessToken = simpleExample.getAccessToken(); |
| | | |
| | | for (DingtalkInfo info : emptyDingtalkIdList) { |
| | | if (StringUtils.hasText(info.getPhone())) { |
| | | try { |
| | | // 通过手机号获取钉钉用户ID |
| | | com.dingtalk.api.response.OapiV2UserGetbymobileResponse response = |
| | | simpleExample.getOapiV2UserGetbymobileResponse(info.getPhone(), accessToken); |
| | | |
| | | if (response != null && response.getResult() != null) { |
| | | info.setDingtalkId(response.getResult().getUserid()); |
| | | // 更新数据库 |
| | | updateById(info); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("获取钉钉用户ID失败,手机号:{}", info.getPhone(), e); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 不存在为空的数据或者处理完空数据后,返回所有有效的dingtalkId列表 |
| | | return list.stream() |
| | | .map(DingtalkInfo::getDingtalkId) |
| | | .filter(StringUtils::hasText) |
| | | .distinct() |
| | | .collect(Collectors.toList()); |
| | | } catch (Exception e) { |
| | | log.error("获取钉钉用户列表失败", e); |
| | | return new ArrayList<>(); |
| | | } |
| | | } |
| | | |
| | | private OapiMessageCorpconversationAsyncsendV2Response sendMessage(String userIdListStr, String message) throws Exception { |
| | | |
| | | String accessToken = simpleExample.getAccessToken(); |
| | | |
| | | DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2"); |
| | | OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request(); |
| | | request.setAgentId(3917187842L); |
| | | request.setAgentId(4104598880L); |
| | | request.setUseridList(userIdListStr); |
| | | request.setToAllUser(false); |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * 发送link消息(在钉钉内置浏览器中打开) |
| | | * |
| | | * @param userIdListStr 用户ID列表,逗号分隔 |
| | | * @param title 消息标题 |
| | | * @param text 消息内容 |
| | | * @param messageUrl 点击消息后跳转的URL |
| | | * @param picUrl 图片URL(可选) |
| | | * @return 响应结果 |
| | | * @throws Exception 异常 |
| | | */ |
| | | private OapiMessageCorpconversationAsyncsendV2Response sendLinkMessage(String userIdListStr, String title, String text, String messageUrl, String picUrl) throws Exception { |
| | | |
| | | String accessToken = simpleExample.getAccessToken(); |
| | | |
| | | DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2"); |
| | | OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request(); |
| | | request.setAgentId(4104598880L); |
| | | request.setUseridList(userIdListStr); |
| | | request.setToAllUser(false); |
| | | |
| | | OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg(); |
| | | msg.setMsgtype("link"); |
| | | msg.setLink(new OapiMessageCorpconversationAsyncsendV2Request.Link()); |
| | | msg.getLink().setTitle(title); |
| | | msg.getLink().setText(text); |
| | | msg.getLink().setMessageUrl(messageUrl); |
| | | if (StringUtils.hasText(picUrl)) { |
| | | msg.getLink().setPicUrl(picUrl); |
| | | } |
| | | request.setMsg(msg); |
| | | |
| | | return client.execute(request, accessToken); |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 发送ActionCard消息(在外部浏览器中打开链接,适合BI等外部系统) |
| | | * |
| | | * @param userIdListStr 用户ID列表,逗号分隔 |
| | | * @param title 消息标题 |
| | | * @param markdown 消息内容(支持Markdown格式) |
| | | * @param singleTitle 按钮文字,例如:"查看详情" |
| | | * @param singleUrl 点击按钮后跳转的URL(外部链接) |
| | | * @return 响应结果 |
| | | * @throws Exception 异常 |
| | | */ |
| | | private OapiMessageCorpconversationAsyncsendV2Response sendActionCardMessage(String userIdListStr, String title, String markdown, String singleTitle, String singleUrl) throws Exception { |
| | | |
| | | String accessToken = simpleExample.getAccessToken(); |
| | | |
| | | DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2"); |
| | | OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request(); |
| | | request.setAgentId(4104598880L); |
| | | request.setUseridList(userIdListStr); |
| | | request.setToAllUser(false); |
| | | |
| | | OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg(); |
| | | msg.setMsgtype("action_card"); |
| | | msg.setActionCard(new OapiMessageCorpconversationAsyncsendV2Request.ActionCard()); |
| | | msg.getActionCard().setTitle(title); |
| | | msg.getActionCard().setMarkdown(markdown); |
| | | msg.getActionCard().setSingleTitle(singleTitle); |
| | | msg.getActionCard().setSingleUrl(singleUrl); |
| | | request.setMsg(msg); |
| | | |
| | | return client.execute(request, accessToken); |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 上传文件到钉钉服务器,获取media_id |
| | | * |
| | | * @param filePath 本地文件路径 |
| | | * @param fileType 文件类型:file(普通文件), voice(语音文件), video(视频文件), image(图片文件) |
| | | * @return media_id |
| | | * @throws Exception 异常 |
| | | */ |
| | | private String uploadMedia(String filePath, String fileType) throws Exception { |
| | | String accessToken = simpleExample.getAccessToken(); |
| | | |
| | | DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/media/upload"); |
| | | com.dingtalk.api.request.OapiMediaUploadRequest request = new com.dingtalk.api.request.OapiMediaUploadRequest(); |
| | | request.setType(fileType); |
| | | |
| | | // 使用 FileItem 包装文件 |
| | | File file = new File(filePath); |
| | | FileItem fileItem = new FileItem(file); |
| | | request.setMedia(fileItem); |
| | | |
| | | com.dingtalk.api.response.OapiMediaUploadResponse response = client.execute(request, accessToken); |
| | | |
| | | if (response.getErrcode() == 0) { |
| | | log.info("文件上传成功,media_id: {}", response.getMediaId()); |
| | | return response.getMediaId(); |
| | | } else { |
| | | log.error("文件上传失败,错误码: {}, 错误信息: {}", response.getErrcode(), response.getErrmsg()); |
| | | throw new Exception("文件上传失败: " + response.getErrmsg()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 通过media_id发送文件消息 |
| | | * |
| | | * @param userIdListStr 用户ID列表,逗号分隔 |
| | | * @param mediaId 文件的media_id(通过uploadMedia方法获取) |
| | | * @return 响应结果 |
| | | * @throws Exception 异常 |
| | | */ |
| | | private OapiMessageCorpconversationAsyncsendV2Response sendFileMessageByMediaId(String userIdListStr, String mediaId) throws Exception { |
| | | |
| | | String accessToken = simpleExample.getAccessToken(); |
| | | |
| | | DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2"); |
| | | OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request(); |
| | | request.setAgentId(4104598880L); |
| | | request.setUseridList(userIdListStr); |
| | | request.setToAllUser(false); |
| | | |
| | | OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg(); |
| | | msg.setMsgtype("file"); |
| | | msg.setFile(new OapiMessageCorpconversationAsyncsendV2Request.File()); |
| | | msg.getFile().setMediaId(mediaId); |
| | | request.setMsg(msg); |
| | | |
| | | return client.execute(request, accessToken); |
| | | |
| | | } |
| | | |
| | | /** |
| | | * 获取isSendDingtalk=1的用户的钉钉用户ID列表(保留原有方法,向后兼容) |
| | | */ |
| | | private List<String> getDingtalkUserIdList() { |