一、场景概述
企业微信作为企业级协同办公平台,其消息通知能力可无缝集成到内部系统中。本文将通过Java代码示例,详细讲解如何快速对接企业微信API,实现自动化消息推送功能,适用于告警通知、审批提醒等业务场景。
二、前置条件准备
- 企业微信管理后台配置
- 登录企业微信管理后台
- 进入「应用管理」→ 创建/选择自建应用
- 记录关键参数:
AgentId(应用ID)Secret(应用密钥)CorpId(企业ID,位于「我的企业」页面)
- 如下图:
- 这里创建了一个用来消息提醒的应用,拿到id和密钥即可。


- 核心代码实现(发送文本消息)
1、配置企业id,应用id和密钥
2、编写配置类用来读取
@Configuration
public class WeChatConfig {
@Value("${wechat.corpId}")
private String corpId;
@Value("${wechat.secret}")
private String secret;
@Value("${wechat.tokenUrl}")
private String tokenUrl;
@Value("${wechat.agentId}")
private String agentId;
// 获取 AccessToken 的 URL
public String getAccessTokenUrl() {
return tokenUrl + "?corpid=" + corpId + "&corpsecret=" + secret;
}
/**
* 其他配置,如 AgentId 等
*/
public String getAgentId() {
return agentId;
}
}3、编写获取企微签名相关代码
注意:这里签名缓存自行设置,不需要每次就去调用企微api,签名失效时间2小时,可自行设置缓存过期时间,我这里利用的redis
@Service
public class WeChatService {
private static final Logger logger = LoggerFactory.getLogger(WeChatService.class);
@Autowired
private WeChatConfig weChatConfig;
/**
* Redis 缓存 access_token 的 key
*/
private static final String QW_ACCESS_TOKEN_CACHE_KEY = "shxd:dekt:qw:access:token";
public String getAccessToken() {
Object redisResult = NHRedisUtils.getRedisResult(QW_ACCESS_TOKEN_CACHE_KEY);
if (redisResult == null) {
String newToken = refreshAccessToken();
if (newToken == null) {
throw new RuntimeException("无法获取企业微信 AccessToken");
}
return newToken;
}
return String.valueOf(redisResult);
}
private String refreshAccessToken() {
try {
String url = weChatConfig.getAccessTokenUrl();
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.getForObject(url, String.class);
JSONObject jsonObject = new JSONObject(response);
logger.error("获取企业微信 token 成功:{}", jsonObject);
String accessToken = jsonObject.getString("access_token");
if (accessToken == null || accessToken.isEmpty()) {
logger.error("获取企业微信 AccessToken 失败,返回为空");
return null;
}
// 加入 Redis,缓存 110 分钟(提前 10 分钟刷新)
NHRedisUtils.addRedis(QW_ACCESS_TOKEN_CACHE_KEY, 110, accessToken);
return accessToken;
} catch (Exception e) {
logger.error("获取企业微信 AccessToken 失败", e);
return null;
}
}
}4、发送消息
@Service
public class WeChatMessageService {
private static final Logger logger = LoggerFactory.getLogger(WeChatMessageService.class);
@Autowired
private WeChatService weChatService;
@Autowired
private WeChatConfig weChatConfig;
private static final String SEND_MESSAGE_URL = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=";
public boolean sendTextMessage(String userId, String content) {
// 获取 AccessToken
String accessToken = weChatService.getAccessToken();
String url = SEND_MESSAGE_URL + accessToken;
// 构造请求体
JSONObject message = new JSONObject();
message.put("touser", userId);
message.put("msgtype", "text");
message.put("agentid", weChatConfig.getAgentId());
JSONObject text = new JSONObject();
text.put("content", content);
message.put("text", text);
try {
RestTemplate restTemplate = new RestTemplate();
// 移除默认的StringHttpMessageConverter(这里防止中文乱码)
restTemplate.getMessageConverters().removeIf(converter ->
converter instanceof StringHttpMessageConverter);
// 添加支持UTF-8的StringHttpMessageConverter
StringHttpMessageConverter converter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
converter.setWriteAcceptCharset(false); // 重要!关闭默认字符集
restTemplate.getMessageConverters().add(0, converter);
// 设置请求头,确保 Content-Type 是 UTF-8
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAcceptCharset(Collections.singletonList(StandardCharsets.UTF_8));
HttpEntity<String> request = new HttpEntity<>(message.toJSONString(), headers);
String response = restTemplate.postForObject(url, request, String.class);
logger.error("发送企业微信消息返回数据:{}", response);
// 解析返回结果
JSONObject jsonResponse = JSONObject.parseObject(response);
int errcode = jsonResponse.getIntValue("errcode");
if (errcode == 0) {
return true;
} else {
logger.error("发送企业微信消息失败,错误码:{},错误信息:{}", errcode, jsonResponse.getString("errmsg"));
return false;
}
} catch (Exception e) {
logger.error("发送企业微信消息请求失败", e);
return false;
}
}
}5、编写controller进行测试
第一个参数为企微用户名,第二个为发送内容。

结果如下:

- 发送图文消息
只需改变消息体即可,如下
// 构造请求体
JSONObject message = new JSONObject();
message.put("touser", userId);
message.put("msgtype", "news");
message.put("agentid", weChatConfig.getAgentId());
// 创建 articles 数组
JSONArray articles = new JSONArray();
JSONObject article = new JSONObject();
article.put("title", "标题"); // 图文标题(必填)
article.put("description", "我是描述"); // 图文描述
article.put("url", "https://xf.xdsisu.edu.cn/ydxg"); // 点击后跳转链接
article.put("picurl", "https://img0.baidu.com/it/u=1077282731,2234353719&fm=253&fmt=auto&app=120&f=JPEG?w=800&h=800"); // 图文封面的图片链接(可选)
articles.add(article);
JSONObject news = new JSONObject();
news.put("articles", articles);
message.put("news", news);
message.put("safe", 0);效果如下:

注意:一定要在应用里面配置可信域名,不然会出现{"errcode":60020,"errmsg":"not allow to access from your ip ip不被允许访问的错误信息

- 扩展
如果是本地图片,没有地址的话,可以调用企微的上传图片接口,会返回给你一个url,这个url在企微内部永久有效。上传图片文档地址
代码如下:
public String uploadImage(byte[] bytes, String accessToken) {
if (bytes == null || bytes.length == 0) {
return null;
}
try {
// 构建请求
String uploadUrl = "https://qyapi.weixin.qq.com/cgi-bin/media/uploadimg?access_token="+accessToken;
HttpEntity<MultiValueMap<String, Object>> requestEntity = buildRequestEntity(bytes);
logger.error("开始上传图片,数据大小:{} bytes", bytes.length);
// 发送请求
ResponseEntity<String> response = restTemplate.postForEntity(uploadUrl, requestEntity, String.class);
// 响应处理
// 解析JSON响应
String responseBody = response.getBody();
if (StringUtils.isBlank(responseBody)) {
logger.error("图片上传返回空响应");
return null;
}
com.alibaba.fastjson.JSONObject json = com.alibaba.fastjson.JSON.parseObject(responseBody);
int errcode = json.getIntValue("errcode");
if (errcode != 0) {
String errmsg = json.getString("errmsg");
logger.error("图片上传失败,错误码:{},错误信息:{}", errcode, errmsg);
return null;
}
String url = json.getString("url");
if (StringUtils.isBlank(url)) {
logger.error("图片上传成功但未返回url");
return null;
}
logger.error("图片上传成功,url:{}", url);
return url;
} catch (RestClientException e) {
logger.error("图片上传请求失败,accessToken:{}", accessToken, e);
} catch (JSONException e) {
logger.error("响应数据解析失败", e);
}
return null;
}
















