向企业微信用户发送消息的实现
企业微信消息推送官方文档
1.工具类
1.1 HttpClientUtils
public class HttpClientUtils {
private static final String CHARSET_UTF8 = "UTF-8";
private static final String CHARSET_GBK = "GBK";
private static final String SSL_DEFAULT_SCHEME = "https";
private static final int SSL_DEFAULT_PORT = 443;
// 异常自动恢复处理, 使用HttpRequestRetryHandler接口实现请求的异常恢复
private static HttpRequestRetryHandler requestRetryHandler = new HttpRequestRetryHandler() {
// 自定义的恢复策略
public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
// 设置恢复策略,在发生异常时候将自动重试3次
if (executionCount >= 3) {
// Do not retry if over max retry count
return false;
}
if (exception instanceof NoHttpResponseException) {
// Retry if the server dropped connection on us
return true;
}
if (exception instanceof SSLHandshakeException) {
// Do not retry on SSL handshake exception
return false;
}
HttpRequest request = (HttpRequest) context.getAttribute(ExecutionContext.HTTP_REQUEST);
boolean idempotent = (request instanceof HttpEntityEnclosingRequest);
if (!idempotent) {
// Retry if the request is considered idempotent
return true;
}
return false;
}
};
// 使用ResponseHandler接口处理响应,HttpClient使用ResponseHandler会自动管理连接的释放,解决了对连接的释放管理
private static ResponseHandler responseHandler = new ResponseHandler() {
// 自定义响应处理
public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
HttpEntity entity = response.getEntity();
if (entity != null) {
String charset = EntityUtils.getContentCharSet(entity) == null ? CHARSET_UTF8 : EntityUtils.getContentCharSet(entity);
return new String(EntityUtils.toByteArray(entity), charset);
} else {
return null;
}
}
};
/**
* Get方式提交,URL中包含查询参数, 格式:http://www.g.cn?search=p&name=s.....
*
* @param url
* 提交地址
* @return 响应消息
* @throws NetServiceException
*/
public static String get(String url) throws NetServiceException {
return get(url, null, null);
}
/**
* Get方式提交,URL中不包含查询参数, 格式:http://www.g.cn
*
* @param url
* 提交地址
* @param params
* 查询参数集, 键/值对
* @return 响应消息
* @throws NetServiceException
*/
public static String get(String url, Map params) throws NetServiceException {
return get(url, params, null);
}
/**
* Get方式提交,URL中不包含查询参数, 格式:http://www.g.cn
*
* @param url
* 提交地址
* @param params
* 查询参数集, 键/值对
* @param charset
* 参数提交编码集
* @return 响应消息
* @throws NetServiceException
*/
public static String get(String url, Map params, String charset) throws NetServiceException {
if (url == null || StringUtil.isEmpty(url)) {
return null;
}
List qparams = getParamsList(params);
if (qparams != null && qparams.size() > 0) {
charset = (charset == null ? CHARSET_UTF8 : charset);
String formatParams = URLEncodedUtils.format(qparams, charset);
url = (url.indexOf("?")) < 0 ? (url + "?" + formatParams) : (url
.substring(0, url.indexOf("?") + 1) + formatParams);
}
DefaultHttpClient httpclient = getDefaultHttpClient(charset);
HttpGet hg = new HttpGet(url);
// 发送请求,得到响应
String responseStr = null;
try {
responseStr = httpclient.execute(hg, responseHandler).toString();
} catch (ClientProtocolException e) {
throw new NetServiceException("客户端连接协议错误", e);
} catch (IOException e) {
throw new NetServiceException("IO操作异常", e);
} finally {
abortConnection(hg, httpclient);
}
return responseStr;
}
/**
* Post方式提交,URL中不包含提交参数, 格式:http://www.g.cn
*
* @param url
* 提交地址
* @param params
* 提交参数集, 键/值对
* @return 响应消息
* @throws NetServiceException
*/
public static String post(String url, Map params) throws NetServiceException {
return post(url, params, null);
}
/**
* Post方式提交,URL中不包含提交参数, 格式:http://www.g.cn
*
* @param url
* 提交地址
* @param params
* 提交参数集, 键/值对
* @param charset
* 参数提交编码集
* @return 响应消息
* @throws NetServiceException
* modified by hxd according to http://blog.csdn.net/rongyongfeikai2/article/details/41659353
*/
public static String post(String url, Map params, String charset) throws NetServiceException {
if (url == null || StringUtil.isEmpty(url)) {
return null;
}
// 创建HttpClient实例
DefaultHttpClient httpclient = getDefaultHttpClient(charset);
UrlEncodedFormEntity formEntity = null;
try {
if (charset == null || StringUtil.isEmpty(charset)) {
formEntity = new UrlEncodedFormEntity(getParamsList(params));
} else {
formEntity = new UrlEncodedFormEntity(getParamsList(params), charset);
}
} catch (UnsupportedEncodingException e) {
throw new NetServiceException("不支持的编码集", e);
}
HttpPost hp = new HttpPost(url);
hp.setEntity(formEntity);
// 发送请求,得到响应
HttpResponse httpResponse = null;
String responseStr = null;
try {
httpResponse = httpclient.execute(hp);
if (null!=httpResponse && HttpStatus.SC_OK == httpResponse.getStatusLine().getStatusCode()) {
HttpEntity entity = httpResponse.getEntity();
if(entity != null){
responseStr = EntityUtils.toString(entity,charset);
}
}
} catch (ClientProtocolException e) {
throw new NetServiceException("客户端连接协议错误", e);
} catch (IOException e) {
throw new NetServiceException("IO操作异常", e);
}
finally {
abortConnection(hp, httpclient);
}
return responseStr;
}
/**
* Post方式提交,忽略URL中包含的参数,解决SSL双向数字证书认证
*
* @param url
* 提交地址
* @param params
* 提交参数集, 键/值对
* @param charset
* 参数编码集
* @param keystoreUrl
* 密钥存储库路径
* @param keystorePassword
* 密钥存储库访问密码
* @param truststoreUrl
* 信任存储库绝路径
* @param truststorePassword
* 信任存储库访问密码, 可为null
* @return 响应消息
* @throws NetServiceException
*/
public static String post(String url, Map params, String charset, final URL keystoreUrl,
final String keystorePassword, final URL truststoreUrl, final String truststorePassword) throws NetServiceException {
if (url == null || StringUtil.isEmpty(url)) {
return null;
}
DefaultHttpClient httpclient = getDefaultHttpClient(charset);
UrlEncodedFormEntity formEntity = null;
try {
if (charset == null || StringUtil.isEmpty(charset)) {
formEntity = new UrlEncodedFormEntity(getParamsList(params));
} else {
formEntity = new UrlEncodedFormEntity(getParamsList(params), charset);
}
} catch (UnsupportedEncodingException e) {
throw new NetServiceException("不支持的编码集", e);
}
HttpPost hp = null;
String responseStr = null;
try {
KeyStore keyStore = createKeyStore(keystoreUrl, keystorePassword);
KeyStore trustStore = createKeyStore(truststoreUrl, keystorePassword);
SSLSocketFactory socketFactory = new SSLSocketFactory(keyStore, keystorePassword, trustStore);
Scheme scheme = new Scheme(SSL_DEFAULT_SCHEME, socketFactory, SSL_DEFAULT_PORT);
httpclient.getConnectionManager().getSchemeRegistry().register(scheme);
hp = new HttpPost(url);
hp.setEntity(formEntity);
//responseStr = httpclient.execute(hp, responseHandler);
} catch (NoSuchAlgorithmException e) {
throw new NetServiceException("指定的加密算法不可用", e);
} catch (KeyStoreException e) {
throw new NetServiceException("keytore解析异常", e);
} catch (CertificateException e) {
throw new NetServiceException("信任证书过期或解析异常", e);
} catch (FileNotFoundException e) {
throw new NetServiceException("keystore文件不存在", e);
} catch (IOException e) {
throw new NetServiceException("I/O操作失败或中断 ", e);
} catch (UnrecoverableKeyException e) {
throw new NetServiceException("keystore中的密钥无法恢复异常", e);
} catch (KeyManagementException e) {
throw new NetServiceException("处理密钥管理的操作异常", e);
} finally {
abortConnection(hp, httpclient);
}
return responseStr;
}
/**
* 获取DefaultHttpClient实例
*
* @param charset
* 参数编码集, 可空
* @return DefaultHttpClient 对象
*/
private static DefaultHttpClient getDefaultHttpClient(final String charset){
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
//模拟浏览器,解决一些服务器程序只允许浏览器访问的问题
httpclient.getParams().setParameter(CoreProtocolPNames.USER_AGENT, "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)");
httpclient.getParams().setParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, Boolean.FALSE);
httpclient.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, charset == null ? CHARSET_UTF8 : charset);
httpclient.setHttpRequestRetryHandler(requestRetryHandler);
return httpclient;
}
/**
* 释放HttpClient连接
*
* @param hrb
* 请求对象
* @param httpclient
* client对象
*/
private static void abortConnection(final HttpRequestBase hrb, final HttpClient httpclient){
if (hrb != null) {
hrb.abort();
}
if (httpclient != null) {
httpclient.getConnectionManager().shutdown();
}
}
/**
* 从给定的路径中加载此 KeyStore
*
* @param url
* keystore URL路径
* @param password
* keystore访问密钥
* @return keystore 对象
*/
private static KeyStore createKeyStore(final URL url, final String password)
throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
if (url == null) {
throw new IllegalArgumentException("Keystore url may not be null");
}
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream is = null;
try {
is = url.openStream();
keystore.load(is, password != null ? password.toCharArray() : null);
} finally {
if (is != null){
is.close();
is = null;
}
}
return keystore;
}
/**
* 将传入的键/值对参数转换为NameValuePair参数集
*
* @param paramsMap
* 参数集, 键/值对
* @return NameValuePair参数集
*/
private static List getParamsList(Map paramsMap) {
if (paramsMap == null || paramsMap.size() == 0) {
return null;
}
List params = new ArrayList();
for ( Object o : paramsMap.entrySet()) {
Map.Entry map = (Map.Entry)o;
params.add(new BasicNameValuePair((String)map.getKey(), (String)map.getValue()));
}
return params;
}
public static String post(String url, String parameters) {
String body = null;
HttpPost method = new HttpPost(url);
DefaultHttpClient httpclient = getDefaultHttpClient("UTF-8");
if (method != null & parameters != null
&& !"".equals(parameters.trim())) {
try {
// 建立一个NameValuePair数组,用于存储欲传送的参数
method.addHeader("Content-type","application/json; charset=utf-8");
method.setHeader("Accept", "application/json");
method.setEntity(new StringEntity(parameters, "UTF-8"));
HttpResponse response = httpclient.execute(method);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
}
body = EntityUtils.toString(response.getEntity());
} catch (IOException e) {
e.printStackTrace();
}
}
return body;
}
}
1.2 WebChatUtil
public class WebChatUtil {
public static String access_token_url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={id}&corpsecret={secrect}";
public static String access_token = null;
private static final Logger logger = Logger.getLogger(WebChatUtil.class);
private static String ERROR_CODE_0 = "0";
private static int callCnt = 0;
/***获取token方法 已验证*/
private static JSONObject doGetStr(String url) throws ClientProtocolException, IOException {
DefaultHttpClient client = new DefaultHttpClient();//获取DefaultHttpClient请求
HttpGet httpGet = new HttpGet(url);//HttpGet将使用Get方式发送请求URL
JSONObject jsonObject = null;
HttpResponse response = client.execute(httpGet);//使用HttpResponse接收client执行httpGet的结果
HttpEntity entity = response.getEntity();//从response中获取结果,类型为HttpEntity
if (entity != null) {
String result = EntityUtils.toString(entity, "UTF-8");//HttpEntity转为字符串类型
jsonObject = JSONObject.fromObject(result);//字符串类型转为JSON类型
}
return jsonObject;
}
private static String getAccessToken(String appid, String appsecret) throws IOException {
String url = access_token_url.replace("{id}", appid).replace("{secrect}", appsecret);//将URL中的两个参数替换掉
JSONObject jsonObject = doGetStr(url);//使用刚刚写的doGet方法接收结果
if (jsonObject != null) { //如果返回不为空,将返回结果封装进AccessToken实体类
try {
String errcode = jsonObject.getString("errcode");
if (ERROR_CODE_0.equals(errcode)) {
access_token = jsonObject.getString("access_token");//取出access_token
} else {
logger.error(jsonObject.getString("errmsg"));
}
} catch (JSONException e) {
access_token = null;
// 获取token失败
}
}
return access_token;
}
public static String getToken() {
if (access_token == null) {
String appid = "CorpID";//企业微信中的ID
String appsecret = "corpsecret";//企业微信中提供的改成自己的
try {
access_token = getAccessToken(appid, appsecret);
} catch (IOException e) {
e.printStackTrace();
}
}
return access_token;
}
public static JSONObject sendWeChatMessageToUser(String touser, String contents){
if(oConvertUtils.isEmpty(touser)){
return new JSONObject();
}
JSONObject jo = sendWeChatMessage(touser, null, null, contents);
String errcode = jo.getString("errcode");
if (!ERROR_CODE_0.equals(errcode)){
logger.error("微信信息发送失败,失败用户:"+touser+",失败原因:"+jo.getString("errmsg")+";发送内容为:"+contents+"。");
}
callCnt = 0;
return jo;
}
/**微信企业号推送消息*/
public static JSONObject sendWeChatMessage(String touser, String toparty, String totag, String contents){
JSONObject jo = new JSONObject();
getToken();
String url="https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={ACCESS_TOKEN}";
url = url.replace("{ACCESS_TOKEN}", access_token);
String agentid = "agentid"; //修改成自己的
JSONObject Jo=new JSONObject();
Jo.put("touser",touser);
if (StringUtil.isNotEmpty(toparty)) {
Jo.put("toparty",toparty);
}
if (StringUtil.isNotEmpty(totag)) {
Jo.put("totag",totag);
}
Jo.put("msgtype","text");
Jo.put("agentid",agentid);
JSONObject content =new JSONObject();
content.put("content",contents);
Jo.put("text",content);
try {
String returnData = HttpClientUtils.post(url, Jo.toString());
jo = JSONObject.fromObject(returnData);
String errcode = jo.getString("errcode");
if (!ERROR_CODE_0.equals(errcode)) {//token过期时重新获取再次请求
if (callCnt < 5) {
callCnt++;
logger.error("token过期,重新获取, 获取时间"+ DateUtils.getTimestamp());
access_token = null;
jo = sendWeChatMessage(touser, toparty, totag, contents);
}
}
} catch (Exception e) {
logger.error(e.getMessage());
}
return jo;
}
}
2.测试方法
public static void main(String[] args) {
WebChatUtil.sendWeChatMessageToUser("TaoYong","你好呀,陶永");
}
3.结果