Spring Cloud Admin添加微信通知

SpringCloud发送微信消息推送参考https://blog.csdn.net/qq_44697754/article/details/128035736

 
 

SpringCloud Admin要增加微信通知,需要继承AbstractStatusChangeNotifier类,在doNotify方法按照模板发送消息。
 
AdminServe添加依赖:


commons-lang
commons-lang
2.3
compile


com.alibaba
fastjson
2.0.21.graal


org.projectlombok
lombok

 
文件application.properties增加配置:

wechat.originalId=gh_dca23axxx
wechat.appId=wx360b2xxxxx
wechat.appsecret=1a7876a7bxxxxxxx
wechat.templateId=-Z6u1ASSqsstKrzxxxxxxxxxxxxx
wechat.accessTokenUrl=https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential
wechat.userGetUrl=https://api.weixin.qq.com/cgi-bin/user/get
wechat.messageSendUrl=https://api.weixin.qq.com/cgi-bin/message/template/send
wechat.templateMassage={"touser":"%s","template_id":"%s",
"data":{"serviceName": {"value":"%s","color":"#00BFFF"},"serviceUrl":{"value":"%s","color":"#00FFFF"},
"status": {"value":"%s","color":"#173177"},"details": {"value":"%s","color":"#EE212D"}}}

 
 

微信接口配置类WechatServiceProperties:

@Getter
@Setter
@Component
@ConfigurationProperties(prefix = "wechat")
public class WechatServiceProperties {

/** 获取access_token的接口地址(GET) 限2000(次/天) */
private String accessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential";

/** 获取关注用户id */
private String userGetUrl = "https://api.weixin.qq.com/cgi-bin/user/get";

/**
* 发送消息url
*/
private String messageSendUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send";

/**
* 模板id
*/
private String templateId = "91921dL1CxrEUms2rnIlKi9_rfmwmiICaiaXxAbhsc8";

/**
* 模板消息
*/
private String templateMassage;

/**
* appId
*/
private String appId;

private String appsecret;

private String originalId;

public String getAccessTokenUrl() {
if (StringUtils.isBlank(accessTokenUrl)) {
throw new IllegalArgumentException("获取access_token的接口地址不能为空");
}

if (StringUtils.isBlank(appId)) {
throw new IllegalArgumentException("appId不能为空");
}

if (StringUtils.isBlank(appsecret)) {
throw new IllegalArgumentException("appsecret不能为空");
}
return String.format(accessTokenUrl+"&appid=%s&secret=%s",appId, appsecret);
}

public String formatGetUserUrl(String accessToken) {
if (StringUtils.isBlank(accessToken)) {
throw new IllegalArgumentException("accessToken不能为空");
}

return String.format(userGetUrl+"?access_token=%s", accessToken);
}

public String formatMessageSendUrl(String accessToken) {
if (StringUtils.isBlank(messageSendUrl)) {
throw new IllegalArgumentException("messageSendUrl不能为空");
}

if (StringUtils.isBlank(accessToken)) {
throw new IllegalArgumentException("accessToken不能为空");
}
return String.format(messageSendUrl+"?access_token=%s", accessToken);
}

public String formatTemplateMassage(TemplateMassageParam param) {
if (StringUtils.isBlank(messageSendUrl)) {
throw new IllegalArgumentException("messageSendUrl不能为空");
}

if (param == null) {
throw new IllegalArgumentException("要发送的消息不能为空");
}
return String.format(templateMassage,param.getTouser(), param.getTemplateId(), param.getServiceName(), param.getServiceUrl(), param.getStatus(), param.getDetails());
}
}

 

 

AccessToken

public class AccessToken implements java.io.Serializable{

private static final long serialVersionUID = -4240357901925120079L;

/** 获取到的凭证 */
private String token;

/** 凭证有效时间,单位:秒 */
private int expiresIn;

public AccessToken() {
}

public AccessToken(String token, int expiresIn) {
this.token = token;
this.expiresIn = expiresIn;
}

public String getToken() {
return token;
}

public void setToken(String token) {
this.token = token;
}

public int getExpiresIn() {
return expiresIn;
}

public void setExpiresIn(int expiresIn) {
this.expiresIn = expiresIn;
}
}

 

HttpUtils用于发送http请求:

Slf4j
public class HttpUtils {

public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {
log.debug("[发起https请求]requestUrl=" + requestUrl);
log.debug("[发起https请求]requestMethod=" + requestMethod);
log.debug("[发起https请求]outputStr=" + outputStr);
JSONObject jsonObject = null;
StringBuffer buffer = new StringBuffer();
try {
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = {new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {

}

@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {

}

@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}};
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();

URL url = new URL(requestUrl);
HttpsURLConnection httpUrlConn = (HttpsURLConnection) url
.openConnection();
httpUrlConn.setSSLSocketFactory(ssf);
httpUrlConn.setDoOutput(true);
httpUrlConn.setDoInput(true);
httpUrlConn.setUseCaches(false);
// 设置请求方式(GET/POST)
httpUrlConn.setRequestMethod(requestMethod);

//if ("GET".equalsIgnoreCase(requestMethod))
httpUrlConn.connect();

// 当有数据需要提交时
if (null != outputStr) {
OutputStream outputStream = httpUrlConn.getOutputStream();
// 注意编码格式,防止中文乱码

outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();

}

// 将返回的输入流转换成字符串
InputStream inputStream = httpUrlConn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(
inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(
inputStreamReader);

String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
// 释放资源
inputStream.close();
httpUrlConn.disconnect();
jsonObject = JSONObject.parseObject(buffer.toString());
} catch (ConnectException ce) {
log.error("Weixin server connection timed out.");
} catch (Exception e) {
log.error("https request error:{}", e);
}
return jsonObject;
}

}

 
 

模板消息参数TemplateMassageParam:

@Setter
@Getter
@Builder
public class TemplateMassageParam {

/**
* 服务名
*/
private String serviceName;

/**
* 服务url
*/
private String serviceUrl;

/**
* 服务状态
*/
private String status;

/**
* 详情
*/
private Map<String, Object> details;

/**
* 发送到的用户
*/
private String touser;

/**
* 消息模板id
*/
private String templateId;
}

 
 

通知发送类WechatNotifier:

@Component
@Slf4j
public class WechatNotifier extends AbstractStatusChangeNotifier {

private Map<String, AccessToken> map = new HashMap<>();

@Autowired
private WechatServiceProperties wechatServiceProperties;

@Autowired
public WechatNotifier(InstanceRepository repository) {
super(repository);
}

@Override
protected Mono doNotify(InstanceEvent event, Instance instance) {
Registration registration = instance.getRegistration();
// 获取关注用户
List users = this.getUsers();
if (users != null && users.size() > 0) {
TemplateMassageParam param = TemplateMassageParam.builder().serviceName(registration.getName())
.serviceUrl(registration.getServiceUrl())
.status(instance.getStatusInfo().getStatus())
.details(instance.getStatusInfo().getDetails())
.templateId(wechatServiceProperties.getTemplateId())
.build();

String sendUrl = wechatServiceProperties.formatMessageSendUrl(map.get("token").getToken());
// 并行遍历推送
users.stream().parallel().forEach(x->{
if (x != null) {
param.setTouser(x);
String templateMassage = wechatServiceProperties.formatTemplateMassage(param);
log.info("[发送模板信息]sendTemplateMessage:"+templateMassage);
JSONObject jsonObject = null;
jsonObject = HttpUtils.httpsRequest(sendUrl, "POST", templateMassage);
log.info("[发送模板信息] sendTemplateMessage result:"+jsonObject);
}
});
}
return Mono.empty();
}

/**
* 获取token
* @return
*/
public AccessToken getAccessToken() {
AccessToken accessToken = null;
String requestUrl = wechatServiceProperties.getAccessTokenUrl();
JSONObject jsonObject=null;
jsonObject = HttpUtils.httpsRequest(requestUrl, "GET", null);
log.info("[(刷新)获取access_token]jsonObject="+jsonObject);
jsonObject = JSONObject.parseObject((String) jsonObject.toString());

if (null != jsonObject) {
try {
accessToken = new AccessToken(jsonObject.getString("access_token"), jsonObject.getInteger("expires_in"));
} catch (JSONException e) {
log.error("获取token失败 errcode:{} errmsg:{}"+jsonObject.getInteger("errcode")+"errmsg:"+jsonObject.getString("errmsg"),e);
}
}
log.info("[获取access_token]jsonObject="+jsonObject);
log.info("[获取access_token]accessToken="+accessToken.getToken());
return accessToken;
}

/**
* 获取关注用户
* @return
*/
public List getUsers() {
try {
log.info("------------ [获取用户信息] ---------------");
String token = null;
AccessToken accessToken = map.get("token");
if (accessToken == null) {
accessToken = this.getAccessToken();
map.put("token",accessToken);
}

if (accessToken != null) {
token = accessToken.getToken();
}
if (token != null) {
String requestUrl = wechatServiceProperties.formatGetUserUrl(token);
JSONObject jsonObject = HttpUtils.httpsRequest(requestUrl, "GET", null);
String dataJson = jsonObject.getString("data");
JSONObject data = JSONObject.parseObject(dataJson);
JSONArray openid = data.getJSONArray("openid");
List list = new ArrayList<>();
if (openid != null && openid.size() > 0) {
for (int i = 0; i < openid.size(); i++) {
Object obj = openid.get(i);
if (obj != null) {
list.add(obj.toString());
}
}
}
return list;
}
} catch (Exception e) {
log.error("[获取关注用户信息]数据异常:",e);
}
return null;
}
}

思路是从微信获取token,在获取关注公众号的用户,按照模板构造消息,向微信接口发送消息。如果发送消息出现data format error错误,应该是模板消息不是正确的JSON格式。修改模板消息成正确的JSON格式。
 

从微信测试公众号可以看到:

posted @ 2023-04-09 13:50  shigp1  阅读(120)  评论(0)    收藏  举报