2026-06-02 11:55:42 +08:00

85 lines
3.3 KiB
Java

package com.company.agentfoundation.integration.wecom;
import com.company.agentfoundation.config.FoundationProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import java.time.Instant;
@Service
public class WecomClient {
private static final Logger log = LoggerFactory.getLogger(WecomClient.class);
private final FoundationProperties properties;
private final WebClient webClient;
private volatile String cachedToken;
private volatile Instant tokenExpireAt = Instant.EPOCH;
public WecomClient(FoundationProperties properties, WebClient.Builder builder) {
this.properties = properties;
this.webClient = builder.baseUrl("https://qyapi.weixin.qq.com").build();
}
public void sendText(String toUser, String content) {
log.info("wecom sendText start toUser={} agentId={} contentPreview={}", toUser, properties.getWecom().getAgentId(), preview(content));
String token = getAccessToken();
WecomSendMessageRequest req = new WecomSendMessageRequest();
req.setToUser(toUser);
req.setAgentId(properties.getWecom().getAgentId());
WecomSendMessageRequest.Text text = new WecomSendMessageRequest.Text();
text.setContent(content);
req.setText(text);
WecomApiResponse response = webClient.post()
.uri(uriBuilder -> uriBuilder.path("/cgi-bin/message/send").queryParam("access_token", token).build())
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(req)
.retrieve()
.bodyToMono(WecomApiResponse.class)
.block();
if (response == null || !response.success()) {
log.error("wecom sendText failed toUser={} err={}", toUser, response == null ? "null" : response.errmsg());
throw new IllegalStateException("WeCom send failed: " + (response == null ? "null" : response.errmsg()));
}
log.info("wecom sendText success toUser={}", toUser);
}
private String getAccessToken() {
if (cachedToken != null && Instant.now().isBefore(tokenExpireAt)) {
log.info("wecom gettoken use cached token expireAt={}", tokenExpireAt);
return cachedToken;
}
WecomTokenResponse response = webClient.get()
.uri(uriBuilder -> uriBuilder.path("/cgi-bin/gettoken")
.queryParam("corpid", properties.getWecom().getCorpId())
.queryParam("corpsecret", properties.getWecom().getSecret())
.build())
.retrieve()
.bodyToMono(WecomTokenResponse.class)
.block();
if (response == null || !response.success() || response.accessToken() == null) {
log.error("wecom gettoken failed err={}", response == null ? "null" : response.errmsg());
throw new IllegalStateException("WeCom gettoken failed: " + (response == null ? "null" : response.errmsg()));
}
cachedToken = response.accessToken();
int expires = response.expiresIn() == null ? 7200 : response.expiresIn();
tokenExpireAt = Instant.now().plusSeconds(Math.max(300, expires - 120));
log.info("wecom gettoken success expireAt={}", tokenExpireAt);
return cachedToken;
}
private String preview(String text) {
if (text == null || text.isBlank()) {
return "";
}
return text.length() <= 80 ? text : text.substring(0, 80) + "...";
}
}