|
@@ -0,0 +1,256 @@
|
|
|
|
+package com.nokia.dingtalkapi.service.impl;
|
|
|
|
+
|
|
|
|
+import java.time.Duration;
|
|
|
|
+import java.util.HashMap;
|
|
|
|
+import java.util.Map;
|
|
|
|
+
|
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
+import org.springframework.core.io.FileSystemResource;
|
|
|
|
+import org.springframework.data.redis.core.RedisTemplate;
|
|
|
|
+import org.springframework.http.HttpEntity;
|
|
|
|
+import org.springframework.http.HttpHeaders;
|
|
|
|
+import org.springframework.http.MediaType;
|
|
|
|
+import org.springframework.http.ResponseEntity;
|
|
|
|
+import org.springframework.util.LinkedMultiValueMap;
|
|
|
|
+import org.springframework.util.MultiValueMap;
|
|
|
|
+import org.springframework.web.client.RestTemplate;
|
|
|
|
+
|
|
|
|
+import com.fasterxml.jackson.core.JsonProcessingException;
|
|
|
|
+import com.fasterxml.jackson.databind.JsonNode;
|
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
+import com.nokia.dingtalkapi.properties.DingtalkProperties;
|
|
|
|
+import com.nokia.dingtalkapi.service.DingtalkService;
|
|
|
|
+
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
+
|
|
|
|
+@Slf4j
|
|
|
|
+public class DingTalkServiceImpl implements DingtalkService {
|
|
|
|
+
|
|
|
|
+ private static final String API_ACCESS_TOKEN_REDIS_KEY = "API_DING_TALK_ACCESS_TOKEN";
|
|
|
|
+ private static final String OAPI_ACCESS_TOKEN_REDIS_KEY = "OAPI_DING_TALK_ACCESS_TOKEN";
|
|
|
|
+
|
|
|
|
+ @Autowired
|
|
|
|
+ private DingtalkProperties properties;
|
|
|
|
+
|
|
|
|
+ @Autowired
|
|
|
|
+ private RestTemplate restTemplate;
|
|
|
|
+
|
|
|
|
+ @Autowired
|
|
|
|
+ private RedisTemplate<String, Object> redisTemplate;
|
|
|
|
+
|
|
|
|
+ @Autowired
|
|
|
|
+ private ObjectMapper objectMapper;
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public String upload(String filePath, String type) {
|
|
|
|
+ String url = "https://oapi.dingtalk.com/media/upload?access_token={0}";
|
|
|
|
+ HttpHeaders httpHeaders = new HttpHeaders();
|
|
|
|
+ httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
|
|
|
|
+
|
|
|
|
+ MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>();
|
|
|
|
+ FileSystemResource fileSystemResource = new FileSystemResource(filePath);
|
|
|
|
+ multiValueMap.add("media", fileSystemResource);
|
|
|
|
+ multiValueMap.add("type", type);
|
|
|
|
+
|
|
|
|
+ HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(multiValueMap, httpHeaders);
|
|
|
|
+
|
|
|
|
+ ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, httpEntity, String.class,
|
|
|
|
+ getOapiToken());
|
|
|
|
+ if (responseEntity.getStatusCode().is2xxSuccessful()) {
|
|
|
|
+ try {
|
|
|
|
+ JsonNode node = objectMapper.readTree(responseEntity.getBody());
|
|
|
|
+ int errcode = node.get("errcode").asInt(-1);
|
|
|
|
+ if (errcode != 0) {
|
|
|
|
+ throw new RuntimeException(node.get("errmsg").asText());
|
|
|
|
+ } else {
|
|
|
|
+ return node.get("media_id").asText();
|
|
|
|
+ }
|
|
|
|
+ } catch (JsonProcessingException e) {
|
|
|
|
+ throw new RuntimeException(e.getMessage());
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ throw new RuntimeException("钉钉api调用失败--"
|
|
|
|
+ + responseEntity.getStatusCodeValue() + "--" + responseEntity.getBody());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public String sendImage(String conversationId, String mediaId) {
|
|
|
|
+ Map<String, Object> msgParam = new HashMap<>();
|
|
|
|
+ msgParam.put("photoURL", mediaId);
|
|
|
|
+
|
|
|
|
+ Map<String, Object> request = new HashMap<>();
|
|
|
|
+ try {
|
|
|
|
+ request.put("msgParam", objectMapper.writeValueAsString(msgParam));
|
|
|
|
+ } catch (JsonProcessingException e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ throw new RuntimeException(e.getMessage());
|
|
|
|
+ }
|
|
|
|
+ request.put("msgKey", "sampleImageMsg");
|
|
|
|
+ request.put("openConversationId", conversationId);
|
|
|
|
+ request.put("robotCode", properties.getAppKey());
|
|
|
|
+ return sendMessage(request);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public String SendFile(String conversationId, String mediaId, String fileName) {
|
|
|
|
+ Map<String, Object> msgParam = new HashMap<>();
|
|
|
|
+ msgParam.put("mediaId", mediaId);
|
|
|
|
+ msgParam.put("fileName", fileName);
|
|
|
|
+ msgParam.put("fileType", fileName.substring(fileName.lastIndexOf('.') + 1));
|
|
|
|
+ Map<String, Object> request = new HashMap<>();
|
|
|
|
+ try {
|
|
|
|
+ request.put("msgParam", objectMapper.writeValueAsString(msgParam));
|
|
|
|
+ } catch (JsonProcessingException e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ throw new RuntimeException(e.getMessage());
|
|
|
|
+ }
|
|
|
|
+ request.put("msgKey", "sampleFile");
|
|
|
|
+ request.put("openConversationId", conversationId);
|
|
|
|
+ request.put("robotCode", properties.getAppKey());
|
|
|
|
+ return sendMessage(request);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public String SendText(String conversationId, String msg) {
|
|
|
|
+ Map<String, Object> msgParam = new HashMap<>();
|
|
|
|
+ msgParam.put("content", msg);
|
|
|
|
+ Map<String, Object> request = new HashMap<>();
|
|
|
|
+ try {
|
|
|
|
+ request.put("msgParam", objectMapper.writeValueAsString(msgParam));
|
|
|
|
+ } catch (JsonProcessingException e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ throw new RuntimeException(e.getMessage());
|
|
|
|
+ }
|
|
|
|
+ request.put("msgKey", "sampleText");
|
|
|
|
+ request.put("openConversationId", conversationId);
|
|
|
|
+ request.put("robotCode", properties.getAppKey());
|
|
|
|
+ return sendMessage(request);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public String sendMarkdown(String conversationId, String msg) {
|
|
|
|
+ Map<String, Object> msgParam = new HashMap<>();
|
|
|
|
+ msgParam.put("text", msg);
|
|
|
|
+
|
|
|
|
+ Map<String, Object> request = new HashMap<>();
|
|
|
|
+ try {
|
|
|
|
+ request.put("msgParam", objectMapper.writeValueAsString(msgParam));
|
|
|
|
+ } catch (JsonProcessingException e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ throw new RuntimeException(e.getMessage());
|
|
|
|
+ }
|
|
|
|
+ request.put("msgKey", "sampleMarkdown");
|
|
|
|
+ request.put("openConversationId", conversationId);
|
|
|
|
+ request.put("robotCode", properties.getAppKey());
|
|
|
|
+ return sendMessage(request);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private String sendMessage(Map<String, Object> request) {
|
|
|
|
+ String url = "https://api.dingtalk.com/v1.0/robot/groupMessages/send";
|
|
|
|
+
|
|
|
|
+ HttpHeaders httpHeaders = new HttpHeaders();
|
|
|
|
+ httpHeaders.setContentType(MediaType.APPLICATION_JSON);
|
|
|
|
+ httpHeaders.set("x-acs-dingtalk-access-token", getApiToken());
|
|
|
|
+
|
|
|
|
+ HttpEntity<Map<String, Object>> httpEntity = new HttpEntity<>(request, httpHeaders);
|
|
|
|
+
|
|
|
|
+ ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, httpEntity, String.class);
|
|
|
|
+ if (responseEntity.getStatusCode().is2xxSuccessful()) {
|
|
|
|
+ JsonNode node;
|
|
|
|
+ try {
|
|
|
|
+ node = objectMapper.readTree(responseEntity.getBody());
|
|
|
|
+ if (node.get("processQueryKey") != null) {
|
|
|
|
+ return node.get("processQueryKey").asText();
|
|
|
|
+ } else {
|
|
|
|
+ throw new RuntimeException("api返回格式有误--" + responseEntity.getBody());
|
|
|
|
+ }
|
|
|
|
+ } catch (JsonProcessingException e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ throw new RuntimeException(e.getMessage());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ throw new RuntimeException("钉钉API调用失败..." + responseEntity.getStatusCodeValue() + ":"
|
|
|
|
+ + responseEntity.getBody());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 获取钉钉api access token
|
|
|
|
+ *
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ private String getApiToken() {
|
|
|
|
+ Object token = redisTemplate.opsForValue().get(API_ACCESS_TOKEN_REDIS_KEY + properties.getAppKey());
|
|
|
|
+ if (token == null) {
|
|
|
|
+ // 调用api获取accessToken
|
|
|
|
+ String url = "https://api.dingtalk.com/v1.0/oauth2/accessToken";
|
|
|
|
+ HttpHeaders headers = new HttpHeaders();
|
|
|
|
+ headers.setContentType(MediaType.APPLICATION_JSON);
|
|
|
|
+
|
|
|
|
+ Map<String, Object> request = new HashMap<>();
|
|
|
|
+ request.put("appKey", properties.getAppKey());
|
|
|
|
+ request.put("appSecret", properties.getAppSecret());
|
|
|
|
+ HttpEntity<Map<String, Object>> httpEntity = new HttpEntity<Map<String, Object>>(request, headers);
|
|
|
|
+
|
|
|
|
+ // 发送请求
|
|
|
|
+ ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, httpEntity, String.class);
|
|
|
|
+ log.info("请求新的api accessToken--{}", responseEntity.getStatusCode());
|
|
|
|
+ if (responseEntity.getStatusCode().is2xxSuccessful()) {
|
|
|
|
+ try {
|
|
|
|
+ JsonNode node = objectMapper.readTree(responseEntity.getBody());
|
|
|
|
+ if (node.get("accessToken") != null) {
|
|
|
|
+ // 添加到缓存,缓存时间比返回的时间短10秒
|
|
|
|
+ token = node.get("accessToken").asText();
|
|
|
|
+ redisTemplate.boundValueOps(API_ACCESS_TOKEN_REDIS_KEY + properties.getAppKey())
|
|
|
|
+ .set(token, Duration.ofSeconds(node.get("expireIn").asLong(3600L) - 10L));
|
|
|
|
+ } else {
|
|
|
|
+ throw new RuntimeException("api返回格式有误--" + responseEntity.getBody());
|
|
|
|
+ }
|
|
|
|
+ } catch (JsonProcessingException e) {
|
|
|
|
+ throw new RuntimeException(e.getMessage());
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ throw new RuntimeException("钉钉api调用失败..."
|
|
|
|
+ + responseEntity.getStatusCodeValue() + ":" + responseEntity.getBody());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return (String) token;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 获取钉钉oapi access token
|
|
|
|
+ *
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ private String getOapiToken() {
|
|
|
|
+ Object token = redisTemplate.opsForValue().get(OAPI_ACCESS_TOKEN_REDIS_KEY + properties.getAppKey());
|
|
|
|
+
|
|
|
|
+ if (token == null) {
|
|
|
|
+ String url = "https://oapi.dingtalk.com/gettoken?appkey={0}&appsecret={1}";
|
|
|
|
+
|
|
|
|
+ ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class, properties.getAppKey(),
|
|
|
|
+ properties.getAppSecret());
|
|
|
|
+ log.info("请求新的oapi accessToken--{}--{}", responseEntity.getStatusCode(), responseEntity.getBody());
|
|
|
|
+ if (responseEntity.getStatusCode().is2xxSuccessful()) {
|
|
|
|
+ try {
|
|
|
|
+ JsonNode node = objectMapper.readTree(responseEntity.getBody());
|
|
|
|
+ int code = node.get("errcode").asInt(-1);
|
|
|
|
+ if (code == 0) {
|
|
|
|
+ // 添加到缓存
|
|
|
|
+ token = node.get("access_token").asText();
|
|
|
|
+ redisTemplate.boundValueOps(OAPI_ACCESS_TOKEN_REDIS_KEY + properties.getAppKey())
|
|
|
|
+ .set(token, Duration.ofSeconds(node.get("expires_in").asLong(3600L) - 10L));
|
|
|
|
+ } else {
|
|
|
|
+ throw new RuntimeException(node.get("errmsg").asText());
|
|
|
|
+ }
|
|
|
|
+ } catch (JsonProcessingException e) {
|
|
|
|
+ throw new RuntimeException(e.getMessage());
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ throw new RuntimeException("钉钉api调用失败..."
|
|
|
|
+ + responseEntity.getStatusCodeValue() + ":" + responseEntity.getBody());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return (String) token;
|
|
|
|
+ }
|
|
|
|
+}
|