轻松实现企业级消息推送,5分钟搞定企业微信集成!
在当今企业协作环境中,实时通知系统是提高团队效率的关键。本文将手把手教你如何通过Spring Boot实现企业微信的应用消息推送和群机器人通知,帮助企业快速构建高效的消息通知体系。
一、前期准备
1. 企业微信注册与配置
-
访问企业微信官网注册企业账号
-
在管理后台→"应用管理"→"创建应用"
- 填写应用名称(如"通知中心")
- 记录
AgentId
和Secret
-
获取企业ID:
- 我的企业→企业信息→记录
企业ID
- 我的企业→企业信息→记录
-
配置群机器人:
- 进入目标群聊→右上角菜单→添加群机器人
- 自定义名称(如"系统监控机器人")
- 复制生成的
Webhook URL
2. 必要的配置参数整理
参数类型 | 参数位置 | 用途说明 |
---|---|---|
CORP_ID | 我的企业→企业信息 | 企业唯一标识 |
AGENT_ID | 应用详情页面 | 应用标识 |
APP_SECRET | 应用详情页面 | 应用密钥 |
WEBHOOK_URL | 群机器人详情页面 | 群机器人消息推送地址 |
二、项目搭建与依赖导入
1. 添加依赖(pom.xml)
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- OkHttp3 -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.10.0</version>
</dependency>
</dependencies>
三、核心代码实现
1. 配置参数管理(application.yml)
wechat:
corp:
corp-id: $YOUR_CORP_ID
agent-id: $YOUR_AGENT_ID
app-secret: $YOUR_APP_SECRET
webhook:
robot: $YOUR_WEBHOOK_URL
2. 配置类(WechatConfig.java)
@Configuration
@Data
public class WechatConfig {
@Value("${wechat.corp.corp-id}")
private String corpId;
@Value("${wechat.corp.agent-id}")
private int agentId;
@Value("${wechat.corp.app-secret}")
private String appSecret;
@Value("${wechat.webhook.robot}")
private String robotWebhook;
}
3. 获取AccessToken工具类
@Component
@RequiredArgsConstructor
public class WechatTokenUtil {
private final WechatConfig wechatConfig;
// 使用ConcurrentHashMap缓存AccessToken
private static final Map<String, String> TOKEN_CACHE = new ConcurrentHashMap<>();
public String getAccessToken() throws IOException {
String key = wechatConfig.getCorpId() + wechatConfig.getAgentId();
String token = TOKEN_CACHE.get(key);
if (token == null || isTokenExpired(token)) {
refreshAccessToken();
token = TOKEN_CACHE.get(key);
}
return token;
}
private void refreshAccessToken() throws IOException {
String url = String.format("https://qyapi.weixin.qq.com/cgi-bin/gettoken?" +
"corpid=%s&corpsecret=%s",
wechatConfig.getCorpId(),
wechatConfig.getAppSecret());
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
String responseBody = response.body().string();
JsonObject json = JsonParser.parseString(responseBody).getAsJsonObject();
if (json.get("errcode").getAsInt() == 0) {
String newToken = json.get("access_token").getAsString();
int expiresIn = json.get("expires_in").getAsInt();
// 使用双重检查锁确保线程安全
synchronized (TOKEN_CACHE) {
String key = wechatConfig.getCorpId() + wechatConfig.getAgentId();
TOKEN_CACHE.put(key, newToken);
}
}
}
}
}
private boolean isTokenExpired(String token) {
// 实际项目中实现过期检查逻辑
return false;
}
}
4. 发送应用消息服务
@Service
@RequiredArgsConstructor
public class AppMsgService {
private final WechatConfig wechatConfig;
private final WechatTokenUtil tokenUtil;
public boolean sendTextMsgToUser(String userId, String content) throws IOException {
String accessToken = tokenUtil.getAccessToken();
String url = String.format("https://qyapi.weixin.qq.com/cgi-bin/message/send?" +
"access_token=%s", accessToken);
Map<String, Object> msg = new HashMap<>();
msg.put("touser", userId);
msg.put("msgtype", "text");
msg.put("agentid", wechatConfig.getAgentId());
Map<String, String> textContent = new HashMap<>();
textContent.put("content", content);
msg.put("text", textContent);
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, new Gson().toJson(msg));
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) return false;
String responseBody = response.body().string();
JsonObject json = JsonParser.parseString(responseBody).getAsJsonObject();
return json.get("errcode").getAsInt() == 0;
}
}
}
5. 发送群机器人消息服务
@Service
@RequiredArgsConstructor
public class RobotMsgService {
private final WechatConfig wechatConfig;
public boolean sendTextToGroup(String content) throws IOException {
String url = wechatConfig.getRobotWebhook();
Map<String, Object> msg = new HashMap<>();
msg.put("msgtype", "text");
Map<String, String> textContent = new HashMap<>();
textContent.put("content", content);
msg.put("text", textContent);
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
RequestBody body = RequestBody.create(mediaType, new Gson().toJson(msg));
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) return false;
String responseBody = response.body().string();
JsonObject json = JsonParser.parseString(responseBody).getAsJsonObject();
return json.get("errcode").getAsInt() == 0;
}
}
}
6. 控制器示例(MsgController.java)
@RestController
@RequestMapping("/api/msg")
@RequiredArgsConstructor
public class MsgController {
private final AppMsgService appMsgService;
private final RobotMsgService robotMsgService;
@PostMapping("/send-to-user")
public ResponseEntity<String> sendToUser(
@RequestParam String userId,
@RequestParam String content) {
try {
boolean success = appMsgService.sendTextMsgToUser(userId, content);
return success ?
ResponseEntity.ok("消息发送成功") :
ResponseEntity.status(500).body("消息发送失败");
} catch (Exception e) {
return ResponseEntity.status(500).body("服务器错误:" + e.getMessage());
}
}
@PostMapping("/send-to-group")
public ResponseEntity<String> sendToGroup(@RequestParam String content) {
try {
boolean success = robotMsgService.sendTextToGroup(content);
return success ?
ResponseEntity.ok("群消息发送成功") :
ResponseEntity.status(500).body("群消息发送失败");
} catch (Exception e) {
return ResponseEntity.status(500).body("服务器错误:" + e.getMessage());
}
}
}
四、功能测试
使用Postman发送测试请求:
1. 应用消息测试
POST /api/msg/send-to-user?userId=@all&content=您好,系统已成功上线!
2. 群机器人测试
POST /api/msg/send-to-group?content=【服务器监控】警告:CPU使用率已达95%!
五、关键注意事项
1. AccessToken管理策略
- 定时刷新:建议每2小时刷新一次AccessToken(官方有效期7200秒)
- 全局缓存:使用Redis或Caffeine缓存AccessToken
- 并发控制:获取Token时使用锁机制防止重复获取
2. 安全性注意事项
// 消息内容敏感信息加密示例
public String encryptContent(String content) {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "AES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] encrypted = cipher.doFinal(content.getBytes());
return Base64.getEncoder().encodeToString(encrypted);
} catch (Exception e) {
throw new RuntimeException("内容加密失败", e);
}
}
3. 企业微信限制
-
消息频率限制:
- 应用消息:每应用每秒上限2000次
- 群机器人:每机器人每分钟发送20条
-
消息内容限制:
- 文本消息最大长度:2048字节
- markdown消息最大长度:4096字节
-
最佳实践建议:
- 重要操作通知添加消息模板
- 异常通知使用@功能指定负责人
- 大文本信息改用Markdown格式
六、扩展能力
支持多种消息类型
只需修改消息体结构,即可支持更多消息类型:
// 发送Markdown消息示例
public boolean sendMarkdownMsg(String content) throws IOException {
// ...
Map<String, Object> msg = new HashMap<>();
msg.put("msgtype", "markdown");
Map<String, String> markdownContent = new HashMap<>();
markdownContent.put("content", content);
msg.put("markdown", markdownContent);
// ...
}
// 发送图片消息示例
public boolean sendImageMsg(byte[] imageData) throws IOException {
// ...
Map<String, Object> msg = new HashMap<>();
msg.put("msgtype", "image");
Map<String, String> imageContent = new HashMap<>();
String mediaId = uploadMedia(imageData); // 先上传素材
imageContent.put("media_id", mediaId);
msg.put("image", imageContent);
// ...
}
七、总结
通过本文介绍,我们实现了Spring Boot与企业微信的全面对接,包括:
- 企业微信应用消息推送
- 群机器人自动通知
- AccessToken智能管理
- 多种消息类型支持
这些功能可广泛应用于:
- 系统监控报警 🚨
- 审批流程通知 📝
- 定时任务报告 ⏱
- 数据更新提醒 📈
最后:如果这篇教程对您有帮助,欢迎点赞收藏⭐!在实际使用过程中遇到任何问题,欢迎在评论区留言,我会第一时间解答!关注我获取更多Spring Boot集成实践教程!