企业微信开发第一步获取AccessToken,企业微信的AccessToken和公众号的不一样,企业微信所有接口调用只需要一个AccessToken,而公众号授权和jssdk是分开的
一、获取企业微信AccessToken
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bootdo.common.cache.RedisService;
import com.bootdo.common.utils.Errors;
import com.bootdo.wx.entity.WxAgent;
import com.bootdo.wx.mapper.WxAgentMapper;
import com.hyd.weixin.utils.HttpSender;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/**
* 处理企业微信AccessToken
* @author laowang
* @email open@xcloud.com
*/
@Slf4j
@Service
public class WeixinAccessTokenService {
//企业微信
public static final String URL_PATTERN2 = "https://qyapi.weixin.qq.com/cgi-bin/gettoken" +
"?corpid={{APPID}}&corpsecret={{SECRET}}";
@Autowired
WxAgentMapper wxAgentMapper;
@Autowired
RedisService redisService;
public String getEnterpriseAccessToken(String account) throws IOException {
String accessToken = "";
WxAgent wxAgent = selectAgent(account);
if (wxAgent == null) {
throw Errors.Account_MissingAccount.ex(account);
}
String url = URL_PATTERN2
.replace("{{APPID}}", wxAgent.getCorpid())
.replace("{{SECRET}}", wxAgent.getAgentSecret());
if(redisService.keyExists("enterprise_"+wxAgent.getAgentId())){
accessToken = redisService.get("enterprise_"+wxAgent.getAgentId());
}else{
HttpSender httpSender = new HttpSender(url);
String json = httpSender.sendAndGetResponse();
JSONObject jsonObject = JSON.parseObject(json);
if (jsonObject.getInteger("errcode")==0) {
accessToken = jsonObject.getString("access_token");
redisService.set("enterprise_"+wxAgent.getAgentId(),accessToken,7200, TimeUnit.SECONDS);
}else{
log.error("企业号获取AccessToken错误 原因{}",jsonObject.getString("errmsg"));
}
}
return accessToken;
}
public WxAgent selectAgent(String account) {
return wxAgentMapper.selectWxAgent(account);
}
}
注:这里获取AccessToken根据自己业务来,做好AccessToken缓存
二、对所有消息类型的枚举
public interface WxTempConstant {
public final String TEMP_TEXT = "text";
public final String TEMP_IMAGE = "image";
public final String TEMP_VOICE = "voice";
public final String TEMP_VIDEO = "video";
public final String TEMP_FILE = "file";
public final String TEMP_TEXT_CARD = "textcard";
public final String TEMP_NEWS = "news";
public final String TEMP_MPNEWS = "mpnews";
public final String TEMP_MARKDOWN = "markdown";
public final String TEMP_MINIPROGEAM_NOTICE = "miniprogram_notice";
public final String TEMP_TASK_CARD = "taskcard";
}
三、封装消息节点结构接口
import java.util.List;
import java.util.Map;
/**
* (description)
* created at 2017/9/30
*
* @author laowang
*/
public interface MapInitializer<K, V> {
void init(Map<K, V> m);
void initListMap(List<Map<K, V>> m);
}
四、封装消息发送类
package com.bootdo.wx.service.wechat;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bootdo.common.utils.MapInitializer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 处理企业微信消息推送操作
*
* @author laowang
* @email open@xcloud.com
*/
@Slf4j
@Service
public class WeixinMessageService {
//企业微信
public static final String URL_PATTERN = "https://qyapi.weixin.qq.com/cgi-bin/message/send" +
"?access_token={{ACCESS_TOKEN}}";
@Autowired
WeixinAccessTokenService weixinAccessTokenService;
/**
* 推送企业消息给用户
*
* @param agentId 应用ID
* @param touser 成员ID列表(消息接收者,多个接收者用‘|’分隔,最多支持1000个)。特殊情况:指定为@all,则向关注该企业应用的全部成员发送
* @param toparty 部门ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
* @param totag 标签ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
* @param msgtype 消息类型
* @param initializer 消息主体参数参考 https://work.weixin.qq.com/api/doc#90000/90135/90236
*/
public void send(String msgtype, String touser, String toparty, String totag, MapInitializer<String, String> initializer, String agentId) {
log.info("企业应用{}发送{}消息给{}", agentId, msgtype, touser);
//准备构造json
JSONObject firstjsonObject = new JSONObject();
JSONObject msgtypejsonObject = new JSONObject();
//图文类json构造
JSONArray jsonArray = new JSONArray();
JSONObject secandjsonObject = new JSONObject();
//填充消息参数
Map<String, String> map = new HashMap<>();
//填充图文类多节点参数
List<Map<String, String>> list = new ArrayList<>();
//构造通用消息参数json
firstjsonObject.put("touser", touser);
firstjsonObject.put("toparty", toparty);
firstjsonObject.put("totag", totag);
firstjsonObject.put("msgtype", msgtype);
firstjsonObject.put("agentid", agentId);
switch (msgtype) {
case "text":
initializer.init(map);
//构造消息主体json
for (String paramName : map.keySet()) {
msgtypejsonObject.put(paramName, map.get(paramName));
}
firstjsonObject.put("text", msgtypejsonObject);
firstjsonObject.put("safe", 0);
break;
case "image":
initializer.init(map);
//构造消息主体json
for (String paramName : map.keySet()) {
msgtypejsonObject.put(paramName, map.get(paramName));
}
firstjsonObject.put("image", msgtypejsonObject);
firstjsonObject.put("safe", 0);
break;
case "voice":
initializer.init(map);
//构造消息主体json
for (String paramName : map.keySet()) {
msgtypejsonObject.put(paramName, map.get(paramName));
}
firstjsonObject.put("voice", msgtypejsonObject);
break;
case "video":
initializer.init(map);
//构造消息主体json
for (String paramName : map.keySet()) {
msgtypejsonObject.put(paramName, map.get(paramName));
}
firstjsonObject.put("video", msgtypejsonObject);
firstjsonObject.put("safe", 0);
break;
case "file":
initializer.init(map);
//构造消息主体json
for (String paramName : map.keySet()) {
msgtypejsonObject.put(paramName, map.get(paramName));
}
firstjsonObject.put("file", msgtypejsonObject);
firstjsonObject.put("safe", 0);
break;
case "textcard":
initializer.init(map);
//构造消息主体json
for (String paramName : map.keySet()) {
msgtypejsonObject.put(paramName, map.get(paramName));
}
firstjsonObject.put("textcard", msgtypejsonObject);
break;
case "news":
initializer.initListMap(list);
//构造消息主体json
for (int i = 0; i <= list.size() - 1; i++) {
secandjsonObject = new JSONObject();
for (String paramName : list.get(i).keySet()) {
secandjsonObject.put(paramName, list.get(i).get(paramName));
}
jsonArray.add(secandjsonObject);
}
log.info(jsonArray.toJSONString());
msgtypejsonObject.put("articles", jsonArray);
firstjsonObject.put("news", msgtypejsonObject);
break;
case "mpnews":
initializer.initListMap(list);
//构造消息主体json
for (int i = 0; i <= list.size() - 1; i++) {
secandjsonObject = new JSONObject();
for (String paramName : list.get(i).keySet()) {
secandjsonObject.put(paramName, list.get(i).get(paramName));
}
jsonArray.add(secandjsonObject);
}
log.info(jsonArray.toJSONString());
msgtypejsonObject.put("articles", jsonArray);
firstjsonObject.put("mpnews", msgtypejsonObject);
break;
case "markdown":
initializer.init(map);
//构造消息主体json
for (String paramName : map.keySet()) {
msgtypejsonObject.put(paramName, map.get(paramName));
}
firstjsonObject.put("markdown", msgtypejsonObject);
break;
case "miniprogram_notice":
initializer.init(map);
initializer.initListMap(list);
//构造消息主体json
for (String paramName : map.keySet()) {
msgtypejsonObject.put(paramName, map.get(paramName));
}
//构造消息节点json
for (int i = 0; i <= list.size() - 1; i++) {
secandjsonObject = new JSONObject();
for (String paramName : list.get(i).keySet()) {
secandjsonObject.put(paramName, list.get(i).get(paramName));
}
jsonArray.add(secandjsonObject);
}
log.info(jsonArray.toJSONString());
msgtypejsonObject.put("content_item", jsonArray);
firstjsonObject.put("miniprogram_notice", msgtypejsonObject);
break;
case "taskcard":
initializer.init(map);
initializer.initListMap(list);
//构造消息主体json
for (String paramName : map.keySet()) {
msgtypejsonObject.put(paramName, map.get(paramName));
}
//构造消息节点json
for (int i = 0; i <= list.size() - 1; i++) {
secandjsonObject = new JSONObject();
for (String paramName : list.get(i).keySet()) {
secandjsonObject.put(paramName, list.get(i).get(paramName));
}
jsonArray.add(secandjsonObject);
}
log.info(jsonArray.toJSONString());
msgtypejsonObject.put("btn", jsonArray);
firstjsonObject.put("taskcard", msgtypejsonObject);
break;
}
sendTo(agentId, firstjsonObject.toJSONString());
}
/**
* 推送消息
* @param agentId
* @param tempdata
*/
public void sendTo(String agentId, String tempdata) {
String accessToken = null;
try {
accessToken = weixinAccessTokenService.getEnterpriseAccessToken(agentId);
} catch (IOException e) {
e.printStackTrace();
}
String url = URL_PATTERN.replace("{{ACCESS_TOKEN}}", accessToken);
JSONObject jsonObject = post(url, tempdata);
if (!StringUtils.isEmpty(jsonObject.toJSONString()) && jsonObject.getInteger("errcode") == 0) {
log.info("消息推送成功");
} else {
log.info("消息推送失败 原因:{}", jsonObject.toJSONString());
}
}
/**
* POST请求的RAW参数传递
*
* @param url
* @param body
* @return
*/
public static JSONObject post(String url, String body) {
JSONObject jsonObject = null;
CloseableHttpClient httpClient = null;
HttpPost httpPost = null;
try {
httpClient = HttpClients.createDefault();
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(20000).setConnectTimeout(20000).build();
httpPost = new HttpPost(url);
httpPost.setConfig(requestConfig);
httpPost.setEntity(new StringEntity(body, "utf-8"));
CloseableHttpResponse response = httpClient.execute(httpPost);
HttpEntity httpEntity = response.getEntity();
jsonObject = JSONObject.parseObject(EntityUtils.toString(httpEntity, "utf-8"));
return jsonObject;
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
return jsonObject;
}
}
}
五、各类型消息推送单元测试(消息主体参数参考 https://work.weixin.qq.com/api/doc#90000/90135/90236)
package com.bootdo;
import com.bootdo.common.utils.MapInitializer;
import com.bootdo.common.utils.wechat.WxTempConstant;
import com.bootdo.wx.service.wechat.WeixinMessageService;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class BootdoApplicationTests {
@Autowired
WeixinMessageService weixinMessageService;
@Test
public void contextLoads() throws IOException {
final String agentId = "1000002";
final String touser = "WangLinJun";
final String toparty = "";
final String totag = "";
//文本消息
try {
weixinMessageService.send(WxTempConstant.TEMP_TEXT, touser, toparty, totag,
new MapInitializer<String, String>() {
@Override
public void init(Map<String, String> m) {
m.put("content", "你的快递已到,请携带工卡前往邮件中心领取。\n出发前可查看<a href=\"http://work.weixin.qq.com\">邮件中心视频实况</a>,聪明避开排队。");
}
@Override
public void initListMap(List<Map<String, String>> m) {
}
}, agentId);
} catch (Exception e) {
log.error("发送模板消息失败: " + e.getMessage());
e.printStackTrace();
}
//图片消息
try {
weixinMessageService.send(WxTempConstant.TEMP_IMAGE, touser, toparty, totag,
new MapInitializer<String, String>() {
@Override
public void init(Map<String, String> m) {
m.put("media_id", "MEDIA_ID");
}
@Override
public void initListMap(List<Map<String, String>> m) {
}
}, agentId);
} catch (Exception e) {
log.error("发送模板消息失败: " + e.getMessage());
e.printStackTrace();
}
//语音消息
try {
weixinMessageService.send(WxTempConstant.TEMP_VOICE, touser, toparty, totag,
new MapInitializer<String, String>() {
@Override
public void init(Map<String, String> m) {
m.put("media_id", "MEDIA_ID");
}
@Override
public void initListMap(List<Map<String, String>> m) {
}
}, agentId);
} catch (Exception e) {
log.error("发送模板消息失败: " + e.getMessage());
e.printStackTrace();
}
//视频消息
try {
weixinMessageService.send(WxTempConstant.TEMP_VIDEO, touser, toparty, totag,
new MapInitializer<String, String>() {
@Override
public void init(Map<String, String> m) {
m.put("media_id", "MEDIA_ID");
}
@Override
public void initListMap(List<Map<String, String>> m) {
}
}, agentId);
} catch (Exception e) {
log.error("发送模板消息失败: " + e.getMessage());
e.printStackTrace();
}
//文件消息
try {
weixinMessageService.send(WxTempConstant.TEMP_FILE, touser, toparty, totag,
new MapInitializer<String, String>() {
@Override
public void init(Map<String, String> m) {
m.put("media_id", "MEDIA_ID");
}
@Override
public void initListMap(List<Map<String, String>> m) {
}
}, agentId);
} catch (Exception e) {
log.error("发送模板消息失败: " + e.getMessage());
e.printStackTrace();
}
//文本卡片消息
try {
weixinMessageService.send(WxTempConstant.TEMP_TEXT_CARD, touser, toparty, totag,
new MapInitializer<String, String>() {
@Override
public void init(Map<String, String> m) {
m.put("title", "领奖通知");
m.put("description", "<div class=\"gray\">2016年9月26日</div> <div class=\"normal\">恭喜你抽中iPhone 7一台,领奖码:xxxx</div><div class=\"highlight\">请于2016年10月10日前联系行政同事领取</div>");
m.put("url", "URL");
m.put("btntxt", "更多");
}
@Override
public void initListMap(List<Map<String, String>> m) {
}
}, agentId);
} catch (Exception e) {
log.error("发送模板消息失败: " + e.getMessage());
e.printStackTrace();
}
//图文消息
try {
weixinMessageService.send(WxTempConstant.TEMP_NEWS, touser, toparty, totag,
new MapInitializer<String, String>() {
@Override
public void init(Map<String, String> m) {
}
@Override
public void initListMap(List<Map<String, String>> m) {
Map<String, String> m1 = new HashMap<>();
m1.put("title", "中秋节礼品领取1");
m1.put("description", "今年中秋节公司有豪礼相送");
m1.put("url", "http://www.baidu.com");
m1.put("picurl", "http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png");
m.add(m1);
Map<String, String> m2 = new HashMap<>();
m2.put("title", "中秋节礼品领取2");
m2.put("description", "今年中秋节公司有豪礼相送");
m2.put("url", "http://www.baidu.com");
m2.put("picurl", "http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png");
m.add(m2);
}
}, agentId);
} catch (Exception e) {
log.error("发送模板消息失败: " + e.getMessage());
e.printStackTrace();
}
//图文消息(mpnews)
try {
weixinMessageService.send(WxTempConstant.TEMP_MPNEWS, touser, toparty, totag,
new MapInitializer<String, String>() {
@Override
public void init(Map<String, String> m) {
}
@Override
public void initListMap(List<Map<String, String>> m) {
Map<String, String> m1 = new HashMap<>();
m1.put("title", "Title");
m1.put("thumb_media_id", "MEDIA_ID");
m1.put("author", "Author");
m1.put("content_source_url", "URL");
m1.put("content", "content");
m1.put("digest", "Digest description");
m.add(m1);
Map<String, String> m2 = new HashMap<>();
m2.put("title", "Title");
m2.put("thumb_media_id", "MEDIA_ID");
m2.put("author", "Author");
m2.put("content_source_url", "URL");
m2.put("content", "content");
m2.put("digest", "Digest description");
m.add(m2);
}
}, agentId);
} catch (Exception e) {
log.error("发送模板消息失败: " + e.getMessage());
e.printStackTrace();
}
//markdown消息
try {
weixinMessageService.send(WxTempConstant.TEMP_MARKDOWN, touser, toparty, totag,
new MapInitializer<String, String>() {
@Override
public void init(Map<String, String> m) {
m.put("content", "markdown content");
}
@Override
public void initListMap(List<Map<String, String>> m) {
}
}, agentId);
} catch (Exception e) {
log.error("发送模板消息失败: " + e.getMessage());
e.printStackTrace();
}
//小程序通知消息
try {
weixinMessageService.send(WxTempConstant.TEMP_MINIPROGEAM_NOTICE, touser, toparty, totag,
new MapInitializer<String, String>() {
@Override
public void init(Map<String, String> m) {
m.put("appid", "appid");
m.put("page", "pages/index?userid=zhangsan&orderid=123123123");
m.put("title", "会议室预订成功通知");
m.put("description", "appid");
m.put("emphasis_first_item", "true");
}
@Override
public void initListMap(List<Map<String, String>> m) {
Map<String, String> m1 = new HashMap<>();
m1.put("key", "会议室");
m1.put("value", "402");
m.add(m1);
Map<String, String> m2 = new HashMap<>();
m2.put("key", "会议室1");
m2.put("value", "403");
m.add(m2);
}
}, agentId);
} catch (Exception e) {
log.error("发送模板消息失败: " + e.getMessage());
e.printStackTrace();
}
//任务卡片消息
try {
weixinMessageService.send(WxTempConstant.TEMP_TASK_CARD, touser, toparty, totag,
new MapInitializer<String, String>() {
@Override
public void init(Map<String, String> m) {
m.put("appid", "appid");
m.put("page", "pages/index?userid=zhangsan&orderid=123123123");
m.put("title", "会议室预订成功通知");
m.put("description", "appid");
m.put("emphasis_first_item", "true");
}
@Override
public void initListMap(List<Map<String, String>> m) {
Map<String, String> m1 = new HashMap<>();
m1.put("key", "会议室");
m1.put("value", "402");
m.add(m1);
Map<String, String> m2 = new HashMap<>();
m2.put("key", "会议室1");
m2.put("value", "403");
m.add(m2);
}
}, agentId);
} catch (Exception e) {
log.error("发送模板消息失败: " + e.getMessage());
e.printStackTrace();
}
}
}
以上代码请根据自己的业务进行更改