项目需求利用钉钉做工作通知发送给个人功能,由于用公司内网,程序设置代理的设置看了无数帖子,吐血整理出测试成功的代码,供有需求的人取之。
一、准备工作
1.在钉钉开放平台创建应用,获取应用凭证(AgentId、AppKey、AppSecret)
2.在pom.xml中写入钉钉依赖
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dingtalk</artifactId>
<version>1.3.95</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>alibaba-dingtalk-service-sdk</artifactId>
<version>2.0.0</version>
</dependency>
二、实现代理
由于钉钉开发文档中没有设置代理这个功能,只能是修改源码进行代理设置
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkConstants;
import com.dingtalk.api.DingTalkSignatureUtil;
import com.taobao.api.*;
import com.taobao.api.internal.parser.json.ObjectJsonParser;
import com.taobao.api.internal.util.*;
import javax.net.ssl.*;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import static com.taobao.api.internal.util.WebV2Utils.*;
public class DefaultProxyDingTalkClient extends DefaultDingTalkClient {
private static boolean ignoreSSLCheck = true;
private static boolean ignoreHostCheck = true;
public DefaultProxyDingTalkClient(String serverUrl, Proxy proxy) {
super(serverUrl);
this.setProxy(proxy);
}
@Override
public <T extends TaobaoResponse> T execute(TaobaoRequest<T> request, String session) throws ApiException {
if (request.getTopApiCallType() == null || request.getTopApiCallType().equals(DingTalkConstants.CALL_TYPE_TOP)) {
return super.execute(request, session);
} else {
return executeOApi(request, session);
}
}
@Override
public <T extends TaobaoResponse> T execute(TaobaoRequest<T> request, String accessKey, String accessSecret, String suiteTicket, String corpId) throws ApiException {
if (request.getTopApiCallType() == null || request.getTopApiCallType().equals(DingTalkConstants.CALL_TYPE_TOP)) {
return super.execute(request, null);
} else {
return executeOApi(request, null, accessKey, accessSecret, suiteTicket, corpId);
}
}
private <T extends TaobaoResponse> T executeOApi(TaobaoRequest<T> request, String session) throws ApiException {
return executeOApi(request, session, null, null, null, null);
}
private <T extends TaobaoResponse> T executeOApi(TaobaoRequest<T> request, String session, String accessKey, String accessSecret, String suiteTicket, String corpId) throws ApiException {
long start = System.currentTimeMillis();
// 构建响应解释器
TaobaoParser<T> parser = null;
if (this.needEnableParser) {
parser = new ObjectJsonParser<T>(request.getResponseClass(), true);
}
// 本地校验请求参数
if (this.needCheckRequest) {
try {
request.check();
} catch (ApiRuleException e) {
T localResponse = null;
try {
localResponse = request.getResponseClass().newInstance();
} catch (Exception xe) {
throw new ApiException(xe);
}
localResponse.setErrorCode(e.getErrCode());
localResponse.setMsg(e.getErrMsg());
return localResponse;
}
}
RequestParametersHolder requestHolder = new RequestParametersHolder();
TaobaoHashMap appParams = new TaobaoHashMap(request.getTextParams());
requestHolder.setApplicationParams(appParams);
// 添加协议级请求参数
TaobaoHashMap protocalMustParams = new TaobaoHashMap();
protocalMustParams.put(DingTalkConstants.ACCESS_TOKEN, session);
requestHolder.setProtocalMustParams(protocalMustParams);
try {
String fullUrl;
// 签名优先
if (accessKey != null) {
Long timestamp = System.currentTimeMillis();
// 验证签名有效性
String canonicalString = DingTalkSignatureUtil.getCanonicalStringForIsv(timestamp, suiteTicket);
String signature = DingTalkSignatureUtil.computeSignature(accessSecret, canonicalString);
Map<String, String> ps = new HashMap<String, String>();
ps.put("accessKey", accessKey);
ps.put("signature", signature);
ps.put("timestamp", timestamp + "");
if (suiteTicket != null) {
ps.put("suiteTicket", suiteTicket);
}
if (corpId != null) {
ps.put("corpId", corpId);
}
String queryStr = DingTalkSignatureUtil.paramToQueryString(ps, "utf-8");
if (this.serverUrl.indexOf("?") > 0) {
fullUrl = this.serverUrl + "&" + queryStr;
} else {
fullUrl = this.serverUrl + "?" + queryStr;
}
} else {
if (this.serverUrl.indexOf("?") > 0) {
fullUrl = this.serverUrl + (session != null && session.length() > 0 ? ("&access_token=" + session) : "");
} else {
fullUrl = this.serverUrl + (session != null && session.length() > 0 ? ("?access_token=" + session) : "");
}
}
HttpResponseData data = null;
// 是否需要压缩响应
if (this.useGzipEncoding) {
request.getHeaderMap().put(Constants.ACCEPT_ENCODING, Constants.CONTENT_ENCODING_GZIP);
}
if ("GET".equals(request.getTopHttpMethod())) {
data = doGet(fullUrl, appParams, Constants.CHARSET_UTF8, connectTimeout, readTimeout);
} else {
// 是否需要上传文件
if (request instanceof TaobaoUploadRequest) {
TaobaoUploadRequest<T> uRequest = (TaobaoUploadRequest<T>) request;
Map<String, FileItem> fileParams = TaobaoUtils.cleanupMap(uRequest.getFileParams());
//todo 这里添加代理, 可以进入WebV2Utils 类中,参考接口调用时, 传参proxy的地方,自己改写下
data = WebV2Utils.doPost(fullUrl, appParams, fileParams, Constants.CHARSET_UTF8, connectTimeout, readTimeout, request.getHeaderMap());
} else {
Map<String, Object> jsonParams = new HashMap<String, Object>();
for (Map.Entry<String, String> paramEntry : appParams.entrySet()) {
String key = paramEntry.getKey();
String value = paramEntry.getValue();
if (value.startsWith("[") && value.endsWith("]")) {
List<Map<String, Object>> childMap = (List<Map<String, Object>>) TaobaoUtils.jsonToObject(value);
jsonParams.put(key, childMap);
} else if (value.startsWith("{") && value.endsWith("}")) {
Map<String, Object> childMap = (Map<String, Object>) TaobaoUtils.jsonToObject(value);
jsonParams.put(key, childMap);
} else {
jsonParams.put(key, value);
}
}
data = doPostWithJson(fullUrl, jsonParams, Constants.CHARSET_UTF8, connectTimeout, readTimeout);
}
}
requestHolder.setResponseBody(data.getBody());
requestHolder.setResponseHeaders(data.getHeaders());
} catch (IOException e) {
TaobaoLogger.logApiError("_dingtalk_", request.getApiMethodName(), serverUrl, requestHolder.getAllParams(), System.currentTimeMillis() - start, e.toString());
throw new ApiException(e);
}
T tRsp = null;
if (this.needEnableParser) {
tRsp = parser.parse(requestHolder.getResponseBody(), Constants.RESPONSE_TYPE_DINGTALK_OAPI);
tRsp.setBody(requestHolder.getResponseBody());
} else {
try {
tRsp = request.getResponseClass().newInstance();
tRsp.setBody(requestHolder.getResponseBody());
} catch (Exception e) {
throw new ApiException(e);
}
}
tRsp.setParams(appParams);
if (!tRsp.isSuccess()) {
TaobaoLogger.logApiError("_dingtalk_", request.getApiMethodName(), serverUrl, requestHolder.getAllParams(), System.currentTimeMillis() - start, tRsp.getBody());
}
return tRsp;
}
public HttpResponseData doGet(String url, Map<String, String> params, String charset, int connectTimeout, int readTimeout) throws IOException {
HttpURLConnection conn = null;
String rsp = null;
HttpResponseData data = new HttpResponseData();
try {
String ctype = "application/x-www-form-urlencoded;charset=" + charset;
String query = buildQuery(params, charset);
conn = getConnection(buildGetUrl(url, query), "GET", ctype, (Map) null, this.getProxy());
conn.setConnectTimeout(connectTimeout);
conn.setReadTimeout(readTimeout);
rsp = getResponseAsString(conn);
data.setBody(rsp);
data.setHeaders(conn.getHeaderFields());
} finally {
if (conn != null) {
conn.disconnect();
}
}
return data;
}
private static HttpURLConnection getConnection(URL url, String method, String ctype, Map<String, String> headerMap, Proxy proxy) throws IOException {
HttpURLConnection conn = null;
if (proxy == null) {
conn = (HttpURLConnection)url.openConnection();
} else {
conn = (HttpURLConnection)url.openConnection(proxy);
}
if (conn instanceof HttpsURLConnection) {
HttpsURLConnection connHttps = (HttpsURLConnection)conn;
if (ignoreSSLCheck) {
try {
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init((KeyManager[])null, new TrustManager[]{new TrustAllTrustManager()}, new SecureRandom());
connHttps.setSSLSocketFactory(ctx.getSocketFactory());
connHttps.setHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
} catch (Exception var8) {
throw new IOException(var8.toString());
}
} else if (ignoreHostCheck) {
connHttps.setHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
}
conn = connHttps;
}
((HttpURLConnection)conn).setRequestMethod(method);
((HttpURLConnection)conn).setDoInput(true);
((HttpURLConnection)conn).setDoOutput(true);
if (headerMap != null && headerMap.get("TOP_HTTP_DNS_HOST") != null) {
((HttpURLConnection)conn).setRequestProperty("Host", (String)headerMap.get("TOP_HTTP_DNS_HOST"));
} else {
((HttpURLConnection)conn).setRequestProperty("Host", url.getHost());
}
((HttpURLConnection)conn).setRequestProperty("Accept", "text/xml,text/javascript");
((HttpURLConnection)conn).setRequestProperty("User-Agent", "top-sdk-java");
((HttpURLConnection)conn).setRequestProperty("Content-Type", ctype);
if (headerMap != null) {
Iterator var9 = headerMap.entrySet().iterator();
while(var9.hasNext()) {
Map.Entry<String, String> entry = (Map.Entry)var9.next();
if (!"TOP_HTTP_DNS_HOST".equals(entry.getKey())) {
((HttpURLConnection)conn).setRequestProperty((String)entry.getKey(), (String)entry.getValue());
}
}
}
return (HttpURLConnection)conn;
}
private static URL buildGetUrl(String url, String query) throws IOException {
return StringUtils.isEmpty(query) ? new URL(url) : new URL(buildRequestUrl(url, query));
}
protected static String getResponseAsString(HttpURLConnection conn) throws IOException {
String charset = getResponseCharset(conn.getContentType());
if (conn.getResponseCode() < 400) {
String contentEncoding = conn.getContentEncoding();
return "gzip".equalsIgnoreCase(contentEncoding) ? getStreamAsString(new GZIPInputStream(conn.getInputStream()), charset) : getStreamAsString(conn.getInputStream(), charset);
} else {
if (conn.getResponseCode() == 400) {
InputStream error = conn.getErrorStream();
if (error != null) {
return getStreamAsString(error, charset);
}
}
throw new IOException(conn.getResponseCode() + " " + conn.getResponseMessage());
}
}
/**
* 执行请求
* content_type: aplication/json
*
* @param url
* @param params
* @param charset
* @param connectTimeout
* @param readTimeout
* @return
* @throws IOException
*/
private HttpResponseData doPostWithJson(String url, Map<String, Object> params, String charset, int connectTimeout, int readTimeout) throws IOException {
String ctype = "application/json;charset=" + charset;
byte[] content = {};
String body = TaobaoUtils.objectToJson(params);
if (body != null) {
content = body.getBytes(charset);
}
return WebV2Utils.doPost(url, ctype, content, connectTimeout, readTimeout, null, this.getProxy());
}
}
三、编写工具类方法
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiGettokenRequest;
import com.dingtalk.api.request.OapiMessageCorpconversationAsyncsendV2Request;
import com.dingtalk.api.request.OapiUserGetByMobileRequest;
import com.dingtalk.api.response.OapiGettokenResponse;
import com.dingtalk.api.response.OapiMessageCorpconversationAsyncsendV2Response;
import com.dingtalk.api.response.OapiUserGetByMobileResponse;
import com.dzbodyshop.daoke.ep.config.DefaultProxyDingTalkClient;
import com.taobao.api.ApiException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.ArrayList;
import java.util.List;
/**
* @author
* @date 2022/8/25 14:04
*/
public class DingDingToPerUtil {
//代理
private final static String HOST = "xxxxxxx";
private final static int PORT = xxxx;
//AppKey
private final static String DING_APP_KEY = "xxxxxxxxxx";
//AppSecret
private final static String DING_APP_SECRET = "xxxxxxxxxxxxxx";
//AgentId
private final static int DING_AGENT_ID = xxxxxx;
/**
* 获取AccessToken
*
* @return AccessToken
* @throws ApiException
*/
private static String getAccessToken() throws ApiException {
DefaultDingTalkClient client = new DefaultProxyDingTalkClient("https://oapi.dingtalk.com/gettoken", proxy());
OapiGettokenRequest request = new OapiGettokenRequest();
//Appkey
request.setAppkey(DING_APP_KEY);
//Appsecret
request.setAppsecret(DING_APP_SECRET);
/*请求方式*/
request.setHttpMethod("GET");
OapiGettokenResponse response = client.execute(request);
return response.getAccessToken();
}
/**
* 根据手机号获取用户urid
*
* @param mobiles
* @return
* @throws ApiException
*/
private static String getUridByMobile(String mobiles) throws ApiException {
//获取应用密钥
String accessToken = getAccessToken();
String[] mobilesList = mobiles.split(",");
List<String> list = new ArrayList<>();
for (String mobile : mobilesList) {
//根据手机号获取用户信息Urid
DingTalkClient clientByMobile = new DefaultProxyDingTalkClient("https://oapi.dingtalk.com/user/get_by_mobile", proxy());
OapiUserGetByMobileRequest req = new OapiUserGetByMobileRequest();
req.setMobile(mobile);
req.setHttpMethod("GET");
OapiUserGetByMobileResponse rsp = clientByMobile.execute(req, accessToken);
if (rsp.isSuccess()) {
list.add(rsp.getUserid());
}
}
return StringUtils.ListToString(list); // list转为String(逗号分隔)
}
public static Boolean workStatusNotice(String mobiles, String info) throws ApiException {
//获取应用密钥
String accessToken = getAccessToken();
boolean result = true;
//根据手机号获取用户信息Urid
String uridList = getUridByMobile(mobiles);
if (StringUtils.isEmpty(uridList)) {
return false;
}
DingTalkClient client = new DefaultProxyDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2", proxy());
OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
request.setUseridList(uridList); // 接收者的userid列表,最大用户列表长度100。
request.setAgentId(Long.valueOf(DING_AGENT_ID)); // 发送消息时使用的微应用的AgentID
request.setToAllUser(false); //是否发送给企业全部用户
OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
//文本消息
OapiMessageCorpconversationAsyncsendV2Request.Text text = new OapiMessageCorpconversationAsyncsendV2Request.Text();
text.setContent(info);
msg.setMsgtype("text");
msg.setText(text);
request.setMsg(msg);
OapiMessageCorpconversationAsyncsendV2Response response = client.execute(request, accessToken);
result = response.isSuccess();
return result;
}
/**
* 设置代理
*
* @return
*/
private static Proxy proxy() {
return new Proxy(Proxy.Type.HTTP, new InetSocketAddress(HOST, PORT));
}
}
写完收工,希望有帮助。