钉钉机器人推送照片,群推和推个人
# 引入依赖
```
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>alibaba-dingtalk-service-sdk</artifactId>
<version>${dingding.version}</version>
</dependency>
```
# 配置相关的url和密钥
```
# 钉钉接口地址
DING:
URL:
TALK: https://oapi.dingtalk.com/gettoken
TALK_UPLOAD: https://oapi.dingtalk.com/media/upload
TALK_GROUP: https://api.dingtalk.com/v1.0/robot/groupMessages/send
```
```
TALK_BASE: https://oapi.dingtalk.com/robot/send?access_token=
TALK_ASYNCSEND: https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2
# 钉钉相关公共信息
INFORMATION:
APP_KEY: 钉钉的key
APP_SECRET: 钉钉的app_secret
OPEN_CONVERSATION_ID: 对话id,要你通过接口获得
ROBOTCODE: 机器人编码
AGENT_ID: 智能体_id
```
## 注意机器人必须发布,不然会出现机器人编码错误
| ![[Pasted image 20250630153759.png]] | ![[Pasted image 20250630153919.png]] |
| ------------------------------------ | ------------------------------------ |
# 基本准被完毕 开始编写工具类
```
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import java.util.HashMap;
import java.util.Map;
/**
* 钉钉API工具类
*/
@Slf4j
@Component
public class DingTalkUtils {
@Autowired
private RestTemplate restTemplate;
@Value("${DING.URL.TALK_UPLOAD}")
private String uploadUrl;
@Value("${DING.URL.TALK_GROUP}")
private String groupMessageUrl;
@Value("${DING.URL.TALK}")
private String tokenUrl;
@Value("${DING.INFORMATION.APP_KEY}")
private String appKey;
@Value("${DING.INFORMATION.APP_SECRET}")
private String appSecret;
/**
* 获取访问令牌
*
* @return 访问令牌
*/
public String getAccessToken() {
try {
String url = tokenUrl + "?appkey=" + appKey + "&appsecret=" + appSecret;
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
if (response.getStatusCode() == HttpStatus.OK) {
JSONObject jsonObject = JSON.parseObject(response.getBody());
if (jsonObject != null && jsonObject.getInteger("errcode") == 0) {
return jsonObject.getString("access_token");
}
}
log.error("获取钉钉访问令牌失败: {}", response.getBody());
return null;
} catch (Exception e) {
log.error("获取钉钉访问令牌异常", e);
return null;
}
}
/**
* 上传媒体文件到钉钉
*
* @param file 媒体文件
* @param type 媒体类型(image, voice, video, file)
* @return 媒体ID
*/
public String uploadMedia(MultipartFile file, String type) {
try {
String accessToken = getAccessToken();
if (accessToken == null) {
return null;
}
String url = uploadUrl + "?access_token=" + accessToken + "&type=" + type;
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
// 设置请求体
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("media", new MultipartFileResource(file));
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
ResponseEntity<String> response = restTemplate.postForEntity(url, requestEntity, String.class);
if (response.getStatusCode() == HttpStatus.OK) {
JSONObject jsonObject = JSON.parseObject(response.getBody());
if (jsonObject != null && jsonObject.getInteger("errcode") == 0) {
return jsonObject.getString("media_id");
}
}
log.error("上传媒体文件到钉钉失败: {}", response.getBody());
return null;
} catch (Exception e) {
log.error("上传媒体文件到钉钉异常", e);
return null;
}
}
/**
* 发送群消息
*
* @param requestBody 请求体
* @return 是否发送成功
*/
public boolean sendGroupMessage(Map<String, Object> requestBody) {
try {
// 获取访问令牌
String accessToken = getAccessToken();
if (accessToken == null) {
log.error("获取钉钉访问令牌失败,无法发送群消息");
return false;
}
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// 添加钉钉访问令牌到请求头
headers.set("x-acs-dingtalk-access-token", accessToken);
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
ResponseEntity<String> response = restTemplate.postForEntity(groupMessageUrl, requestEntity, String.class);
if (response.getStatusCode() == HttpStatus.OK) {
JSONObject jsonObject = JSON.parseObject(response.getBody());
return jsonObject != null && jsonObject.containsKey("processQueryKey");
}
log.error("发送钉钉群消息失败: {}", response.getBody());
return false;
} catch (Exception e) {
log.error("发送钉钉群消息异常", e);
return false;
}
}
/**
* 发送工作通知消息
*
* @param requestBody 请求体
* @return 是否发送成功
*/
public boolean sendWorkNotification(Map<String, Object> requestBody) {
try {
// 获取访问令牌
String accessToken = getAccessToken();
if (accessToken == null) {
log.error("获取钉钉访问令牌失败,无法发送工作通知");
return false;
}
// 构建URL
String url = "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2?access_token=" + accessToken;
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
ResponseEntity<String> response = restTemplate.postForEntity(url, requestEntity, String.class);
if (response.getStatusCode() == HttpStatus.OK) {
JSONObject jsonObject = JSON.parseObject(response.getBody());
if (jsonObject != null && jsonObject.getInteger("errcode") == 0) {
return true;
}
}
log.error("发送钉钉工作通知失败: {}", response.getBody());
return false;
} catch (Exception e) {
log.error("发送钉钉工作通知异常", e);
return false;
}
}
/**
* 通过手机号获取用户ID
*
* @param mobile 手机号
* @return 用户ID
*/
public String getUserIdByMobile(String mobile) {
try {
// 获取访问令牌
String accessToken = getAccessToken();
if (accessToken == null) {
log.error("获取钉钉访问令牌失败,无法获取用户ID");
return null;
}
// 构建URL
String url = "https://oapi.dingtalk.com/topapi/v2/user/getbymobile?access_token=" + accessToken;
// 构建请求体
Map<String, String> requestBody = new HashMap<>();
requestBody.put("mobile", mobile);
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Map<String, String>> requestEntity = new HttpEntity<>(requestBody, headers);
ResponseEntity<String> response = restTemplate.postForEntity(url, requestEntity, String.class);
if (response.getStatusCode() == HttpStatus.OK) {
JSONObject jsonObject = JSON.parseObject(response.getBody());
if (jsonObject != null && jsonObject.getInteger("errcode") == 0) {
JSONObject result = jsonObject.getJSONObject("result");
if (result != null) {
return result.getString("userid");
}
}
log.error("通过手机号获取用户ID失败: {}", response.getBody());
}
return null;
} catch (Exception e) {
log.error("通过手机号获取用户ID异常", e);
return null;
}
}
}
```
# controller
```
import com.xiao.guang.dingding.service.DingTalkService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.util.HashMap;
import java.util.Map;
/**
* 钉钉机器人控制器
*/
@RestController
@RequestMapping("/api/dingtalk")
public class DingTalkController {
@Autowired
private DingTalkService dingTalkService;
/**
* 上传图片并推送到钉钉群
*
* @param file 上传的图片文件
* @param message 可选的消息文本
* @return 响应结果
*/
@PostMapping("/sendImage")
public ResponseEntity<Map<String, Object>> sendImage(
@RequestParam("file") MultipartFile file,
@RequestParam(value = "message", required = false, defaultValue = "") String message) {
Map<String, Object> result = new HashMap<>();
try {
// 检查文件是否为空
if (file.isEmpty()) {
result.put("success", false);
result.put("message", "请选择要上传的图片");
return ResponseEntity.badRequest().body(result);
}
// 检查文件类型
String contentType = file.getContentType();
if (contentType == null || !contentType.startsWith("image/")) {
result.put("success", false);
result.put("message", "只支持图片文件上传");
return ResponseEntity.badRequest().body(result);
}
// 调用服务发送图片
boolean success = dingTalkService.sendImageToGroup(file, message);
if (success) {
result.put("success", true);
result.put("message", "图片已成功发送到钉钉群");
return ResponseEntity.ok(result);
} else {
result.put("success", false);
result.put("message", "发送图片失败");
return ResponseEntity.internalServerError().body(result);
}
} catch (Exception e) {
result.put("success", false);
result.put("message", "发送图片时发生错误: " + e.getMessage());
return ResponseEntity.internalServerError().body(result);
}
}
/**
* 上传图片并推送给钉钉个人
*
* @param file 上传的图片文件
* @param userId 接收者的用户ID
* @param message 可选的消息文本
* @return 响应结果
*/
@PostMapping("/sendImageToUser")
public ResponseEntity<Map<String, Object>> sendImageToUser(
@RequestParam("file") MultipartFile file,
@RequestParam("userId") String userId,
@RequestParam(value = "message", required = false, defaultValue = "") String message) {
Map<String, Object> result = new HashMap<>();
try {
// 检查文件是否为空
if (file.isEmpty()) {
result.put("success", false);
result.put("message", "请选择要上传的图片");
return ResponseEntity.badRequest().body(result);
}
// 检查文件类型
String contentType = file.getContentType();
if (contentType == null || !contentType.startsWith("image/")) {
result.put("success", false);
result.put("message", "只支持图片文件上传");
return ResponseEntity.badRequest().body(result);
}
// 检查userId是否为空
if (userId == null || userId.isEmpty()) {
result.put("success", false);
result.put("message", "接收者ID不能为空");
return ResponseEntity.badRequest().body(result);
}
// 调用服务发送图片
boolean success = dingTalkService.sendImageToUser(file, userId, message);
if (success) {
result.put("success", true);
result.put("message", "图片已成功发送给用户");
return ResponseEntity.ok(result);
} else {
result.put("success", false);
result.put("message", "发送图片失败");
return ResponseEntity.internalServerError().body(result);
}
} catch (Exception e) {
result.put("success", false);
result.put("message", "发送图片时发生错误: " + e.getMessage());
return ResponseEntity.internalServerError().body(result);
}
}
/**
* 通过手机号上传图片并推送给钉钉个人
*
* @param file 上传的图片文件
* @param mobile 接收者的手机号
* @param message 可选的消息文本
* @return 响应结果
*/
@PostMapping("/sendImageToUserByMobile")
public ResponseEntity<Map<String, Object>> sendImageToUserByMobile(
@RequestParam("file") MultipartFile file,
@RequestParam("mobile") String mobile,
@RequestParam(value = "message", required = false, defaultValue = "") String message) {
Map<String, Object> result = new HashMap<>();
try {
// 检查文件是否为空
if (file.isEmpty()) {
result.put("success", false);
result.put("message", "请选择要上传的图片");
return ResponseEntity.badRequest().body(result);
}
// 检查文件类型
String contentType = file.getContentType();
if (contentType == null || !contentType.startsWith("image/")) {
result.put("success", false);
result.put("message", "只支持图片文件上传");
return ResponseEntity.badRequest().body(result);
}
// 检查手机号是否为空
if (mobile == null || mobile.isEmpty()) {
result.put("success", false);
result.put("message", "接收者手机号不能为空");
return ResponseEntity.badRequest().body(result);
}
// 调用服务发送图片
boolean success = dingTalkService.sendImageToUserByMobile(file, mobile, message);
if (success) {
result.put("success", true);
result.put("message", "图片已成功发送给用户");
return ResponseEntity.ok(result);
} else {
result.put("success", false);
result.put("message", "发送图片失败");
return ResponseEntity.internalServerError().body(result);
}
} catch (Exception e) {
result.put("success", false);
result.put("message", "发送图片时发生错误: " + e.getMessage());
return ResponseEntity.internalServerError().body(result);
}
}
}
```
# service
```
import [org.springframework.web.multipart.MultipartFile](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/multipart/MultipartFile.html);
/**
* 钉钉服务接口
*/
public interface DingTalkService {
/**
* 发送图片到钉钉群
*
* @param imageFile 图片文件
* @param message 可选的消息文本
* @return 是否发送成功
*/
boolean sendImageToGroup(MultipartFile imageFile, String message);
/**
* 发送图片给钉钉个人
*
* @param imageFile 图片文件
* @param userId 接收者的用户ID
* @param message 可选的消息文本
* @return 是否发送成功
*/
boolean sendImageToUser(MultipartFile imageFile, String userId, String message);
/**
* 通过手机号发送图片给钉钉个人
*
* @param imageFile 图片文件
* @param mobile 接收者的手机号
* @param message 可选的消息文本
* @return 是否发送成功
*/
boolean sendImageToUserByMobile(MultipartFile imageFile, String mobile, String message);
}
```
# serviceImp
```
import com.alibaba.fastjson2.JSON;
import com.xiao.guang.dingding.service.DingTalkService;
import com.xiao.guang.dingding.utils.DingTalkUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.util.HashMap;
import java.util.Map;
/**
* 钉钉服务实现
*/
@Slf4j
@Service
public class DingTalkServiceImpl implements DingTalkService {
@Value("${DING.INFORMATION.ROBOTCODE}")
private String robotCode;
@Value("${DING.INFORMATION.OPEN_CONVERSATION_ID}")
private String openConversationId;
@Autowired
private DingTalkUtils dingTalkUtils;
@Value("${DING.INFORMATION.APP_KEY}")
private String appKey;
@Value("${DING.INFORMATION.APP_SECRET}")
private String appSecret;
@Value("${DING.INFORMATION.AGENT_ID}")
private Long agentId;
@Override
public boolean sendImageToGroup(MultipartFile imageFile, String message) {
try {
// 1. 上传图片到钉钉,获取mediaId
String mediaId = dingTalkUtils.uploadMedia(imageFile, "image");
if (mediaId == null || mediaId.isEmpty()) {
log.error("上传图片到钉钉失败");
return false;
}
// 2. 构建发送图片消息的请求体
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("robotCode", robotCode);
requestBody.put("openConversationId", openConversationId);
// 设置msgParam为JSON字符串和msgKey
requestBody.put("msgParam", "{\"photoURL\": \"" + mediaId + "\"}");
requestBody.put("msgKey", "sampleImageMsg");
// 3. 发送消息到钉钉群
return dingTalkUtils.sendGroupMessage(requestBody);
} catch (Exception e) {
log.error("发送图片到钉钉群失败", e);
return false;
}
}
@Override
public boolean sendImageToUser(MultipartFile imageFile, String userId, String message) {
try {
// 1. 上传图片到钉钉,获取mediaId
String mediaId = dingTalkUtils.uploadMedia(imageFile, "image");
if (mediaId == null || mediaId.isEmpty()) {
log.error("上传图片到钉钉失败");
return false;
}
// 2. 构建发送图片消息的请求体
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("agent_id", agentId);
requestBody.put("userid_list", userId);
// 3. 构建消息内容
Map<String, Object> msg = new HashMap<>();
msg.put("msgtype", "image");
// 4. 设置图片信息
Map<String, String> imageContent = new HashMap<>();
imageContent.put("media_id", mediaId);
msg.put("image", imageContent);
// 5. 如果有附加消息,添加文本消息
if (message != null && !message.isEmpty()) {
// 注意:钉钉API不支持在图片消息中直接添加文本,这里只是记录,实际发送时只会发送图片
log.info("附加消息:{},由于钉钉API限制,此消息不会随图片一起发送", message);
}
requestBody.put("msg", msg);
// 6. 发送工作通知消息
return dingTalkUtils.sendWorkNotification(requestBody);
} catch (Exception e) {
log.error("发送图片到钉钉个人失败", e);
return false;
}
}
@Override
public boolean sendImageToUserByMobile(MultipartFile imageFile, String mobile, String message) {
try {
// 1. 通过手机号获取userId
String userId = dingTalkUtils.getUserIdByMobile(mobile);
if (userId == null || userId.isEmpty()) {
log.error("通过手机号获取用户ID失败: {}", mobile);
return false;
}
// 2. 调用现有方法发送图片
return sendImageToUser(imageFile, userId, message);
} catch (Exception e) {
log.error("通过手机号发送图片到钉钉个人失败", e);
return false;
}
}
}
```
# 总结
## 本人亲测有效,这里不放测试截图了,因为代码,让我清理了,需要源码的可以私信我,获取原代码
## 补充一下如何获取对话_id
[获取对话_id](https://open.dingtalk.com/document/orgapp/obtain-group-openconversationid)
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)