SpringCloud发送微信消息推送参考https://blog.csdn.net/qq_44697754/article/details/128035736
。
SpringCloud Admin要增加微信通知,需要继承AbstractStatusChangeNotifier类,在doNotify方法按照模板发送消息。
AdminServe添加依赖:
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.21.graal</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
文件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<Void> doNotify(InstanceEvent event, Instance instance) {
Registration registration = instance.getRegistration();
// 获取关注用户
List<String> 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<String> 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<String> 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格式。
从微信测试公众号可以看到:
标签:jsonObject,String,accessToken,Admin,Spring,token,微信,null,public From: https://www.cnblogs.com/shigongp/p/17300235.html