package com.company.agentfoundation.integration.wecom; import com.company.agentfoundation.config.FoundationProperties; 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 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) { 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()) { throw new IllegalStateException("WeCom send failed: " + (response == null ? "null" : response.errmsg())); } } private String getAccessToken() { if (cachedToken != null && Instant.now().isBefore(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) { 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)); return cachedToken; } }