要推送微信的模板消息,我们需要准备的条件有:
- 1、有效的access_token
- 2、微信公众号提供的消息模板的Template_id
access_token:
公众平台以access_token为接口调用凭据,来调用接口,所有接口的调用需要先获取access_token,access_token在2小时内有效,过期需要重新获取,但1天内获取次数有限,开发者需自行存储,详见获取接口调用凭据(access_token)文档。
这里我使用缓存存储access_token,并定时到微信平台获取更新。
Template_id:
Template_id是我们需要推送的模板消息的模板的唯一标识,微信公众平台提供了很多模板,也支持自定义格式。在实际使用时,我们需要到微信公众平台申请开启模板消息功能。在微信公众平台的首页,左侧菜单有一个“添加功能插件”,选择模板消息,微信平台审核需要一定时间。
消息模板举例:
{{first.DATA}}
告警内容:{{keyword1.DATA}}
告警发生时间:{{keyword2.DATA}}
{{keyword3.DATA}}
为了方便封装数据,我们使用模板类来包装要发送的信息:
TemplateParam 类封装了模板消息中的一个数据,比如上面的“{{first.DATA}} ”,具体属性可阅读注释:
public class TemplateParam {
// 参数名称
private String name;
// 参数值
private String value;
// 颜色
private String color;
public TemplateParam(String name, String value, String color) {
this.name = name;
this.value = value;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
Template类代表了整个微信模板消息,这里我使用了特定的toJSON()方法生成要发送给微信云平台的json数据:
public class Template {
// 消息接收方
private String toUser;
// 模板id
private String templateId;
// 模板消息详情链接
private String url;
// 消息顶部的颜色
// private String topColor;
// 参数列表
private List<TemplateParam> templateParamList;
public String getToUser() {
return toUser;
}
public void setToUser(String toUser) {
this.toUser = toUser;
}
public String getTemplateId() {
return templateId;
}
public void setTemplateId(String templateId) {
this.templateId = templateId;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
// public String getTopColor() {
// return topColor;
// }
//
// public void setTopColor(String topColor) {
// this.topColor = topColor;
// }
public String toJSON() {
StringBuffer buffer = new StringBuffer();
buffer.append("{");
buffer.append(String.format("\"touser\":\"%s\"", this.toUser)).append(",");
buffer.append(String.format("\"template_id\":\"%s\"", this.templateId)).append(",");
// buffer.append(String.format("\"url\":\"%s\"", this.url)).append(",");
// buffer.append(String.format("\"topcolor\":\"%s\"", this.topColor)).append(",");
buffer.append("\"data\":{");
TemplateParam param = null;
for (int i = 0; i < this.templateParamList.size(); i++) {
param = templateParamList.get(i);
// 判断是否追加逗号
if (i < this.templateParamList.size() - 1) {
buffer.append(String.format("\"%s\": {\"value\":\"%s\",\"color\":\"%s\"},", param.getName(), param.getValue(), param.getColor()));
} else {
buffer.append(String.format("\"%s\": {\"value\":\"%s\",\"color\":\"%s\"}", param.getName(), param.getValue(), param.getColor()));
}
}
buffer.append("}");
buffer.append("}");
return buffer.toString();
}
public List<TemplateParam> getTemplateParamList() {
return templateParamList;
}
public void setTemplateParamList(List<TemplateParam> templateParamList) {
this.templateParamList = templateParamList;
}
准备好了模板消息实体,就可以封装数据并发送了。关注公众号的微信用户,会使用openid来唯一标识,下面的方法是实现了多用户群发,for循环逐一发送,目前没有找到更好的群发方法:
@RequestMapping("/sendWarningByWechat")
@ResponseBody
public ResultMap sendWarningByWechat(String openIds, String content, String alarmDescriptions, String sendDateTime) {
ResultMap res = new ResultMap();
StringBuffer resBuff = new StringBuffer();
try {
String templateMsgUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";
templateMsgUrl = templateMsgUrl.replace("ACCESS_TOKEN", MemoryData.access_token);
//封装请求体
Template template = new Template();
template.setTemplateId("0ZUeqUJQ7jxB3G-fxgKyP17SPoo44wFuxnYBqLu5zA4E");
List<TemplateParam> templateParams = new ArrayList<>();
String[] failures = alarmDescriptions.split("\\|\\|");
String alarmDescStr = "\\r\\n";
if (failures != null && failures.length > 0) {
for (String failure : failures) {
alarmDescStr += failure + "\\r\\n";
}
//去掉最后的换行符号
alarmDescStr = alarmDescStr.substring(0, alarmDescStr.lastIndexOf("\\r\\n"));
}
String allStr = content + alarmDescStr;
while (allStr.length() > 180) {
alarmDescStr = alarmDescStr.substring(0, alarmDescStr.lastIndexOf("\\r\\n"))+"...";
allStr = content + alarmDescStr;
}
TemplateParam first = new TemplateParam("first", content + "\\r\\n", "#DB1A1B");
TemplateParam keyword1 = new TemplateParam("keyword1", alarmDescStr + "\\r\\n", "#DB1A1B");
TemplateParam keyword2 = new TemplateParam("keyword2", sendDateTime + "", "#DB1A1B");
TemplateParam keyword3 = new TemplateParam("keyword3", "", "#DB1A1B");
templateParams.add(first);
templateParams.add(keyword1);
templateParams.add(keyword2);
templateParams.add(keyword3);
template.setTemplateParamList(templateParams);
String[] openIdArr = openIds.split(",");
if (openIdArr.length > 0) {
for (String openID : openIdArr) {
template.setToUser(openID);
String paramStr = template.toJSON();
String resJson = HttpClientUtil.doTemplateMsgPost(templateMsgUrl, paramStr);
}
}
} catch (Exception e) {
log.error(e.getMessage());
e.printStackTrace();
res.setFailureResult();
}
return res;
}
给微信云平台发送json数据时,使用Apache的HttpClient,工具方法如下:
/**
* 发送模板消息的方法
* @param templateMsgUrl 模板消息请求URL
* @param paramStr 模板消息json字符串
* @return
*/
public static String doTemplateMsgPost(String templateMsgUrl,String paramStr){
String res=null;
URL url = null;
try {
url = new URL(templateMsgUrl);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
if (null != paramStr) {
OutputStream outputStream = conn.getOutputStream();
// 注意编码格式
outputStream.write(paramStr.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = conn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
StringBuffer buffer = new StringBuffer();
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
// 释放资源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
conn.disconnect();
res=buffer.toString();
} catch (Exception e) {
e.printStackTrace();
}
return res;
}