# 引入依赖
```
 <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)
 

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐