微信公众号模板消息仅用于公众号向用户发送重要的服务通知,只能用于符合其要求的服务场景中,如信用卡刷卡通知,商品购买成功通知等。不支持广告等营销类消息以及其它所有可能对用户造成骚扰的消息。具体模板消息运营规则请读模板消息运营规范
关于使用规则,请注意:
1、所有服务号都可以在功能->添加功能插件处看到申请模板消息功能的入口,但只有认证后的服务号才可以申请模板消息的使用权限并获得该权限;2、需要选择公众账号服务所处的2个行业,每月可更改1次所选行业;3、在所选择行业的模板库中选用已有的模板进行调用;4、每个账号可以同时使用15个模板。5、当前每个账号的模板消息的日调用上限为10万次,单个模板没有特殊限制。【2014年11月18日将接口调用频率从默认的日1万次提升为日10万次,可在MP登录后的开发者中心查看】。当账号粉丝数超过10W/100W/1000W时,模板消息的日调用上限会相应提升,以公众号MP后台开发者中心页面中标明的数字为准。
关于接口文档,请注意:
1、模板消息调用时主要需要模板ID和模板中各参数的赋值内容;
2、模板中参数内容必须以".DATA"结尾,否则视为保留字;
3、模板保留符号"{{ }}"。
一、首先我们要在公众号里面添加我们所需要用到的模板,先假设您已经在MP中设置好了所属行业;
二、然后我们要定义一些请求模板消息时所要使用的实体类
/// <summary>
/// 公众号模板消息
/// </summary>
public class TemplateMessage
{
public TemplateMessage()
{
topcolor = "#FF0000";
}
/// <summary>
/// 接收者微信OpenId
/// </summary>
public string touser { get; set; }
/// <summary>
/// 模板Id
/// </summary>
public string template_id { get; set; }
/// <summary>
/// 跳转url
/// </summary>
public string url { get; set; }
/// <summary>
/// 顶部颜色
/// </summary>
public string topcolor { get; set; }
/// <summary>
/// 具体模板数据
/// </summary>
public object data { get; set; }
}
数据项data
public class TemplateDataItem
{
/// <summary>
/// 项目值
/// </summary>
public string value { get; set; }
/// <summary>
/// 16进制颜色代码,如:#FF0000
/// </summary>
public string color { get; set; }
/// <summary>
///
/// </summary>
/// <param name="v">value</param>
/// <param name="c">color</param>
public TemplateDataItem(string v, string c = "#173177")
{
value = v;
color = c;
}
}
这里就是我们上面在公众号中添加的一些模板:
public class MessageTemplate
{
/// <summary>
/// 领取通知消息模板(优惠券领取成功通知)
/// </summary>
/// <param name="first">通知标题</param>
/// <param name="keyword1">券名称</param>
/// <param name="keyword2">来源商家</param>
/// <param name="keyword3">过期时间</param>
/// <param name="keyword4">使用说明</param>
/// <param name="remark">备注</param>
/// <returns></returns>
public static object NoticeTemplate(string first, string keyword1, string keyword2, string keyword3, string keyword4, string remark)
{
var data = new
{
first = new TemplateDataItem(first, "#3990eb"),
keyword1 = new TemplateDataItem(keyword1, "#feb91a"),
keyword2 = new TemplateDataItem(keyword2, "#feb91a"),
keyword3 = new TemplateDataItem(keyword3, "#feb91a"),
keyword4 = new TemplateDataItem(keyword4, "#000000"),
remark = new TemplateDataItem(remark, "#fe5627")
};
return data;
}
/// <summary>
/// (订单支付成功)消息模板---->>面向消费者
/// </summary>
/// <param name="first">标题</param>
/// <param name="orderMoneySum">支付金额</param>
/// <param name="orderProductName">商品信息</param>
/// <param name="Remark">备注</param>
/// <returns></returns>
public static object NoticeOrderPaySuccess(string first, string orderMoneySum, string orderProductName, string Remark)
{
var data = new
{
first = new TemplateDataItem(first, "#3990eb"),
orderMoneySum = new TemplateDataItem(orderMoneySum, "#feb91a"),
orderProductName = new TemplateDataItem(orderProductName, "#feb91a"),
Remark = new TemplateDataItem(Remark, "#fe5627")
};
return data;
}
/// <summary>
/// (新订单通知)消息模板---->>面向商家
/// </summary>
/// <param name="first">消息标题</param>
/// <param name="keyword1">下单时间</param>
/// <param name="keyword2">配送地址</param>
/// <param name="keyword3">订单金额</param>
/// <param name="keyword4">订单备注</param>
/// <param name="remark"></param>
/// <returns></returns>
public static object NoticeOrderPaySuccess(string first, string keyword1, string keyword2, string keyword3, string keyword4, string remark)
{
var data = new
{
first = new TemplateDataItem(first, "#3990eb"),
keyword1 = new TemplateDataItem(keyword1, "#feb91a"),
keyword2 = new TemplateDataItem(keyword2, "#feb91a"),
keyword3 = new TemplateDataItem(keyword3, "#feb91a"),
keyword4 = new TemplateDataItem(keyword4, "#000000"),
remark = new TemplateDataItem(remark, "#fe5627")
};
return data;
}
}
还有一个消息发送之后微信返回码的一个实体:
public class TemplateDataItem
{
/// <summary>
/// 项目值
/// </summary>
public string value { get; set; }
/// <summary>
/// 16进制颜色代码,如:#FF0000
/// </summary>
public string color { get; set; }
/// <summary>
///
/// </summary>
/// <param name="v">value</param>
/// <param name="c">color</param>
public TemplateDataItem(string v, string c = "#173177")
{
value = v;
color = c;
}
}
/// <summary>
/// JSON返回结果(用于微信响应接口等)
/// </summary>
public class WxJsonResult
{
public ReturnCode errcode { get; set; }
public string errmsg { get; set; }
}
/// <summary>
/// 发送模板消息结果
/// </summary>
public class TemplateMessageResult:WxJsonResult
{
/// <summary>
/// msgid
/// </summary>
public int msgid { get; set; }
}
三、所有实体建好之后我们就需要去写发送模板消息的服务了;
public class SendTemplateMessageService
{
/// <summary>
/// 公众号相关信息
/// </summary>
private const string AppId = "wxdcabc123456xyz";
private const string AppSecret = "086323crd33xd23gc524fd93428b4ed9";
/// <summary>
/// 发送模板消息API
/// </summary>
private const string SendMessageApi = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={0}";
/// <summary>
/// 获取用信息API
/// </summary>
private const string GetBaseUserInfoApi = "https://api.weixin.qq.com/cgi-bin/user/info?access_token={0}&openid={1}&lang=zh_CN";
/// <summary>
/// 公众号发送模板消息方法
/// </summary>
/// <param name="appId"></param>
/// <param name="appSecret"></param>
/// <param name="templateId">模板ID</param>
/// <param name="openId">微信openId</param>
/// <param name="url">点击详情跳转路径</param>
/// <param name="data"></param>
public static void SendTemplateMessage(string templateId, string openId, string url, object data)
{
var accessToken = AccessTokenContainer.TryGetToken(AppId,AppSecret);
var getInfoUrl = string.Format(GetBaseUserInfoApi, accessToken, openId);
var userInfo = HttpClientHelper.GetResponse<WeixinUserInfoResult>(getInfoUrl);
//判断用户是否关注公众号
switch (userInfo.subscribe)
{
case 0:
break;
default:
var sendUrl = string.Format(SendMessageApi, accessToken);
var msg = new TemplateMessage
{
template_id = templateId,
touser = openId,
url = url,
data = data
};
//序列化实体为json
string json = JsonConvert.SerializeObject(msg, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
//调用消息发送接口
var result = HttpClientHelper.PostResponse<TemplateMessageResult>(string.Format(sendUrl, accessToken), json);
LoggerHelper.Log(string.Format("【微信公众号发送模板消息接口调用】返回参数:errcode:{0},erromsg:{1},misgid:{2}", result.errcode, result.errmsg, result.msgid));
break;
}
}
}
四、最后一步就是调用我们上面的这个方法发送模板消息了
//判断是否是在微信浏览器中
if (isWechat)
{
var url = "http://m.xdd.wquan.cn/findcp";
var endDate = "2015年08月20日";
var first = string.Format("恭喜您,获得了100元现金抵用券");
var keyword4 = StrUtil.HtmlDiscode(ecList.ECouponDetail.Usage);
var remark = "点击“详情”查看优惠券,欢迎再次使用享叮当!";
//得到所需要的模板数据
var data = MessageTemplate.NoticeTemplate(first, ecList.ProductName, ecList.CorpName, endDate, keyword4, remark);
//调用发送模板消息的方法,模板Id存储在config中
SendTemplateMessageService.SendTemplateMessage(noticeTemplateId, oAuthAccessTokenResult.openid, url, data);
}
最后来看一下效果:
实例二
1、模板消息解释
微信为防止服务号对用户进行恶意骚扰和营销,而服务号在某些场景又必须给用户发送消息时(如购物成功、支付成功),这时候就可以应用微信提供的模板消息来给用户进行提醒。
比如:
2、怎么添加模板消息?
在微信公众号后台菜单里面有模板消息一栏,点击进去后可以看到模板库,可以根据自己的实际需要添加自己需要的模板消息,模板涵盖各行各业,暂不可自己编辑模板。
微信限制最多只能选择8个模板,应该也够用了。选中模板后就可以看到模板ID、标题等,这里已购买成功为列,查看详情时:
可以看到该模板需要提供的相关参数,这样就可以拼装请求的参数了。
这一步主要是要拿到模板的ID和该模板需要的参数名。
3、怎么请求发送模板?
第一步:获取模板ID
通过在模板消息功能的模板库中使用需要的模板,可以获得模板ID。第二步:请求接口请注意,URL置空,则在发送后,点击模板消息会进入一个空白页面(ios),或无法点击(android)。
POST请求
https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN
其中的POST请求中需要两个基本的技术要点:
1、获取ACCESS_TOKEN。
2、如何提交POST请求。
具体请参考开发教程系列获取ACCESS_TOKEN篇,http://kangliang.iteye.com/admin/blogs/21617
然后组装需要的JSON信息:
如:
{
"touser":"OPENID",
"template_id":"ngqIpbwh8bUfcSsECmogfXcV14J0tQlEpBO27izEYtY",
"url":"http://weixin.qq.com/download",
"topcolor":"#FF0000",
"data": {
"firstData": {
"value":"恭喜您购物成功!",
"color":"#173177"
},
"product": {
"value":"韩版西服",
"color":"#173177"
},
"price": {
"value":"149元",
"color":"#173177"
},
"time": {
"value":"2014-12-04 13:09:17",
"color":"#173177"
},
"remark": {
"value":"感谢您的光临,我们将尽快发货!",
"color":"#173177"
}
}
}
因模板消息属于固定格式,可在代码中写死拼装方式:
组装json信息:
/**
商品购买成功
* templateId 模板ID
* orderId 订单id
*
*/
String toTemplateMsgText(String orderId,String templateId){
OrderResponse response=getOrderByOrderId(orderId);
//查询订单信息
Order order=response.getOrder();
String first="您好,欢迎在新礼特购物!";
String remark="您的收货信息:"+order.getReceiver_name()+"电话:"+order.getReceiver_mobile()+"地址:"+order.getReceiver_city()+order.getReceiver_zone()+order.getReceiver_address()+"我们将尽快发货,祝您购物愉快!";
String jsonText="{"touser":"OPENID","template_id":"templateId","url":"","topcolor":"#FF0000","data":{"first": {"value":"firstData","color":"#173177"},"product": {"value":"productData","color":"#173177"},"price": {"value":"priceData","color":"#173177"},"time": {"value":"timeData","color":"#173177"},"remark": {"value":"remarkData","color":"#173177"}}}";
jsonText= jsonText.replace("firstData", first).replace("templateId", templateId).replace("OPENID", order.getBuyer_openid()).replace("productData", order.getProduct_name()).replace("priceData",order.getOrder_total_price()/100f+"元").replace("timeData", order.getOrder_create_time()).replace("remarkData", remark);
return jsonText;
}
发送消息:
/**
* 发送模板消息
* @param accessToken
* @param jsonData
*/
public static void sendTemplateMsg(String accessToken,String jsonData){
String requestUrl=send_templatemsg_url.replace("ACCESS_TOKEN", accessToken);
JSONObject jsonObject = httpRequest(requestUrl,"GET", jsonData);
if(jsonObject!=null){
if("0".equals(jsonObject.getString("errcode"))){
System.out.println("发送模板消息成功!");
}else{
System.out.println(jsonObject.getString("errcode"));
}
}
}
另附上httpRequest请求方法:
/**
* 发起https请求并获取结果
*
* @param requestUrl 请求地址
* @param requestMethod 请求方式(GET、POST)
* @param outputStr 提交的数据
* @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
*/
public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
JSONObject jsonObject = null;
StringBuffer buffer = new StringBuffer();
try {
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() };
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();
inputStream = null;
httpUrlConn.disconnect();
jsonObject = JSONObject.fromObject(buffer.toString());
} catch (ConnectException ce) {
} catch (Exception e) {
}
return jsonObject;
}
事件推送
在模版消息发送任务完成后,微信服务器会将是否送达成功作为通知,发送到开发者中心中填写的服务器配置地址中。
1、送达成功时,推送的XML如下:
<xml>
<ToUserName><![CDATA[gh_7f083739789a]]></ToUserName>
<FromUserName><![CDATA[oia2TjuEGTNoeX76QEjQNrcURxG8]]&g;</FromUserName>
<CreateTime>1395658920</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[TEMPLATESENDJOBFINISH]]></Event>
<MsgID>200163836</MsgID>
<Status><![CDATA[success]]></Status>
</xml>
2、送达由于用户拒收(用户设置拒绝接收公众号消息)而失败时,推送的XML如下:
<xml>
<ToUserName><![CDATA[gh_7f083739789a]]></ToUserName>
<FromUserName><![CDATA[oia2TjuEGTNoeX76QEjQNrcURxG8]]></FromUserName>
<CreateTime>1395658984</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[TEMPLATESENDJOBFINISH]]></Event>
<MsgID>200163840</MsgID>
<Status><![CDATA[failed:user block]]></Status>
</xml>
在调用模板消息接口后,会返回JSON数据包。正常时的返回JSON数据包示例:
{
"errcode":0,
"errmsg":"ok",
"msgid":200228332
}
在根据相应的事件监听,就可以获取发送的状态,而及时对消息进行重复或其他的操作。