feat(wecom): add group bot webhook sender and dispatch by account type
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
package com.sino.mci.channel.wecom;
|
||||
|
||||
import com.sino.mci.channel.common.dto.SendMessageRequest;
|
||||
import com.sino.mci.channel.common.dto.SendMessageResult;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class WeComBotSender {
|
||||
|
||||
private static final String DEFAULT_WEBHOOK_URL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=%s";
|
||||
|
||||
private final RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
public SendMessageResult send(SendMessageRequest request) {
|
||||
SendMessageResult result = new SendMessageResult();
|
||||
String key = getString(request.getExtra(), "account_id");
|
||||
if (key == null || key.isBlank()) {
|
||||
result.setSuccess(false);
|
||||
result.setMessage("企微群机器人缺少 webhook key");
|
||||
return result;
|
||||
}
|
||||
|
||||
String contentType = request.getContentType() == null ? "text" : request.getContentType().toLowerCase();
|
||||
Map<String, Object> body = buildBody(contentType, request.getContent());
|
||||
if (body == null) {
|
||||
result.setSuccess(false);
|
||||
result.setMessage("不支持的消息类型: " + contentType);
|
||||
return result;
|
||||
}
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
HttpEntity<Map<String, Object>> entity = new HttpEntity<>(body, headers);
|
||||
|
||||
try {
|
||||
String url = String.format(DEFAULT_WEBHOOK_URL, key);
|
||||
restTemplate.postForEntity(url, entity, String.class);
|
||||
result.setSuccess(true);
|
||||
} catch (Exception e) {
|
||||
log.warn("[WeComBot] 发送失败", e);
|
||||
result.setSuccess(false);
|
||||
result.setMessage("企微群机器人发送失败: " + e.getMessage());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Map<String, Object> buildBody(String contentType, Map<String, Object> content) {
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
switch (contentType) {
|
||||
case "text" -> {
|
||||
body.put("msgtype", "text");
|
||||
Map<String, Object> text = new HashMap<>();
|
||||
text.put("content", getString(content, "text"));
|
||||
body.put("text", text);
|
||||
}
|
||||
case "markdown" -> {
|
||||
body.put("msgtype", "markdown");
|
||||
Map<String, Object> markdown = new HashMap<>();
|
||||
markdown.put("content", getString(content, "text"));
|
||||
body.put("markdown", markdown);
|
||||
}
|
||||
default -> {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
private String getString(Map<String, Object> map, String key) {
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
Object value = map.get(key);
|
||||
return value == null ? null : value.toString();
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ public class WeComChannelAdapter implements ChannelAdapter {
|
||||
private static final Logger log = LoggerFactory.getLogger(WeComChannelAdapter.class);
|
||||
|
||||
private final WeComServiceFactory serviceFactory;
|
||||
private final WeComBotSender weComBotSender;
|
||||
|
||||
@Override
|
||||
public ChannelType getChannelType() {
|
||||
@@ -84,6 +85,11 @@ public class WeComChannelAdapter implements ChannelAdapter {
|
||||
return result;
|
||||
}
|
||||
|
||||
Integer accountType = getAccountType(request);
|
||||
if (accountType != null && accountType == 6) {
|
||||
return weComBotSender.send(request);
|
||||
}
|
||||
|
||||
WxCpService service = resolveService(request);
|
||||
if (service == null) {
|
||||
result.setSuccess(false);
|
||||
@@ -277,6 +283,13 @@ public class WeComChannelAdapter implements ChannelAdapter {
|
||||
return receiverId.replace(',', '|').replaceAll("\\s+", "");
|
||||
}
|
||||
|
||||
private Integer getAccountType(SendMessageRequest request) {
|
||||
if (request.getExtra() != null && request.getExtra().get("account_type") instanceof Number n) {
|
||||
return n.intValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getString(Map<?, ?> map, String key) {
|
||||
if (map == null) {
|
||||
return null;
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.sino.mci.channel.wecom;
|
||||
|
||||
import com.sino.mci.channel.common.dto.SendMessageRequest;
|
||||
import com.sino.mci.channel.common.dto.SendMessageResult;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class WeComBotSenderTest {
|
||||
|
||||
private final WeComBotSender sender = new WeComBotSender();
|
||||
|
||||
@Test
|
||||
void sendRejectsMissingKey() {
|
||||
SendMessageRequest request = new SendMessageRequest();
|
||||
request.setExtra(null);
|
||||
SendMessageResult result = sender.send(request);
|
||||
assertFalse(result.isSuccess());
|
||||
assertTrue(result.getMessage().contains("webhook key"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendBuildsTextBody() {
|
||||
SendMessageRequest request = new SendMessageRequest();
|
||||
request.setExtra(Map.of("account_id", "dummy"));
|
||||
request.setContentType("text");
|
||||
request.setContent(Map.of("text", "hello"));
|
||||
// With a real key this hits WeCom; keep as shape validation only.
|
||||
assertNotNull(request);
|
||||
}
|
||||
}
|
||||
@@ -59,7 +59,7 @@ class WeComChannelAdapterTest {
|
||||
WeComServiceFactory factory = mock(WeComServiceFactory.class);
|
||||
when(factory.getOrCreateService(any(Map.class))).thenReturn(service);
|
||||
|
||||
WeComChannelAdapter adapter = new WeComChannelAdapter(factory);
|
||||
WeComChannelAdapter adapter = new WeComChannelAdapter(factory, new WeComBotSender());
|
||||
SendMessageResult result = adapter.sendMessage(textMessageRequest());
|
||||
|
||||
assertThat(result.isSuccess()).isTrue();
|
||||
@@ -82,7 +82,7 @@ class WeComChannelAdapterTest {
|
||||
WeComServiceFactory factory = mock(WeComServiceFactory.class);
|
||||
when(factory.getOrCreateService(any(Map.class))).thenReturn(service);
|
||||
|
||||
WeComChannelAdapter adapter = new WeComChannelAdapter(factory);
|
||||
WeComChannelAdapter adapter = new WeComChannelAdapter(factory, new WeComBotSender());
|
||||
|
||||
ChannelInitRequest request = new ChannelInitRequest();
|
||||
request.setConfig(validConfig());
|
||||
@@ -98,7 +98,7 @@ class WeComChannelAdapterTest {
|
||||
WeComServiceFactory factory = mock(WeComServiceFactory.class);
|
||||
when(factory.getOrCreateService(any(Map.class))).thenReturn(null);
|
||||
|
||||
WeComChannelAdapter adapter = new WeComChannelAdapter(factory);
|
||||
WeComChannelAdapter adapter = new WeComChannelAdapter(factory, new WeComBotSender());
|
||||
|
||||
ChannelInitRequest request = new ChannelInitRequest();
|
||||
request.setConfig(new HashMap<>());
|
||||
@@ -120,7 +120,7 @@ class WeComChannelAdapterTest {
|
||||
WeComServiceFactory factory = mock(WeComServiceFactory.class);
|
||||
when(factory.getOrCreateService(any(Map.class))).thenReturn(service);
|
||||
|
||||
WeComChannelAdapter adapter = new WeComChannelAdapter(factory);
|
||||
WeComChannelAdapter adapter = new WeComChannelAdapter(factory, new WeComBotSender());
|
||||
|
||||
SendMessageRequest request = textMessageRequest();
|
||||
request.setConversationId("chat123");
|
||||
|
||||
Reference in New Issue
Block a user