您的位置:首页 > 移动开发 > 微信开发

微信公众平台开发之模板消息(Java)

2015-07-21 14:33 876 查看
目录(?)[-]

模版消息

具体调用方法

事件推送
返回码说明

一开发模板消息SDK
二构造模板消息并发送

模版消息

由于柳峰老师的新书还没有出来,网上也没有过多介绍基于Java语言的开发微信公众平台模板消息的例子,因此有了本文。由于个人表达能力和编程能力有限,请多多包涵。本文仅介绍拥有模板消息权限的微信公众账号开发。

本文分为以下两部分:

1.开发模板消息SDK

2.构造模板消息并发送

首先看一下模板消息接口文档:


模版消息

我的模板

模板库

返回上一层模板库 /
模板消息接口文档

为了保证用户不受到骚扰,在开发者出现需要主动提醒、通知用户时,才允许开发者在公众平台网站中模板消息库中选择模板,选择后获得模板ID,再根据模板ID向用户主动推送提醒、通知消息。

模板消息调用时主要需要模板ID和模板中各参数的赋值内容。请注意:
1.模板中参数内容必须以".DATA"结尾,否则视为保留字;
2.模板保留符号"{{ }}"

具体调用方法

第一步:获取模板ID
通过在模板消息功能的模板库中使用需要的模板,可以获得模板ID。
第二步:请求接口
请注意,URL置空,则在发送后,点击模板消息会进入一个空白页面(ios),或无法点击(android)。
POST请求
https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN
请求包为一个json:
{
"touser":"OPENID",
"template_id":"ngqIpbwh8bUfcSsECmogfXcV14J0tQlEpBO27izEYtY",
"url":"http://weixin.qq.com/download",
"topcolor":"#FF0000",
"data":{
"User": {
"value":"黄先生",
"color":"#173177"
},
"Date":{
"value":"06月07日 19时24分",
"color":"#173177"
},
"CardNumber":{
"value":"0426",
"color":"#173177"
},
"Type":{
"value":"消费",
"color":"#173177"
},
"Money":{
"value":"人民币260.00元",
"color":"#173177"
},
"DeadTime":{
"value":"06月07日19时24分",
"color":"#173177"
},
"Left":{
"value":"6504.09",
"color":"#173177"
}
}
}


发送效果图:



事件推送
在模版消息发送任务完成后,微信服务器会将是否送达成功作为通知,发送到开发者中心中填写的服务器配置地址中。
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>


3、送达由于其他原因失败时,推送的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: system failed]]></Status>
</xml>


返回码说明
在调用模板消息接口后,会返回JSON数据包。正常时的返回JSON数据包示例:
{
"errcode":0,
"errmsg":"ok",
"msgid":200228332
}

错误时的返回JSON数据,形式类似,错误码请见本页下方返回码说明。

返回码说明
-1系统繁忙
0请求成功
40001验证失败
40002不合法的凭证类型
40003不合法的OpenID
40004不合法的媒体文件类型
40005不合法的文件类型
40006不合法的文件大小
40007不合法的媒体文件id
40008不合法的消息类型
40009不合法的图片文件大小
40010不合法的语音文件大小
40011不合法的视频文件大小
40012不合法的缩略图文件大小
40013不合法的APPID
41001缺少access_token参数
41002缺少appid参数
41003缺少refresh_token参数
41004缺少secret参数
41005缺少多媒体文件数据
41006access_token超时
42001需要GET请求
43002需要POST请求
43003需要HTTPS请求
44001多媒体文件为空
44002POST的数据包为空
44003图文消息内容为空
45001多媒体文件大小超过限制
45002消息内容超过限制
45003标题字段超过限制
45004描述字段超过限制
45005链接字段超过限制
45006图片链接字段超过限制
45007语音播放时间超过限制
45008图文消息超过限制
45009接口调用超过限制
46001不存在媒体数据
47001解析JSON/XML内容错误


一、开发模板消息SDK

模板消息的定义如下:

模板消息也是使用access_token作为授权来发送。但是请大家注意:这里的access_token与网页授权的access_token完全不是一回事。可不要拿网页授权的access_token当作参数传递。

获取模板消息access_token:

String appId = "xxxxxxxxxxxxx"; //公众账号的唯一标识

String appSecret="xxxxxxxxxxx"; //公众账号的密钥

Token token = CommonUtil.getToken(appId, appSecret);

String access_token = token.getAccessToken();

#CommonUtil工具类具体代码:

import java.io.BufferedReader;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.OutputStream;

import java.io.UnsupportedEncodingException;

import java.net.ConnectException;

import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

import javax.net.ssl.SSLContext;

import javax.net.ssl.SSLSocketFactory;

import javax.net.ssl.TrustManager;

import net.sf.json.JSONException;

import net.sf.json.JSONObject;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

/**

* 通用工具类

*

* @author liufeng

*/

public class CommonUtil {

private static Logger log = LoggerFactory.getLogger(CommonUtil.class);

// 凭证获取(GET)

public final static String token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";

/**

* 发送 https 请求

*

* @param requestUrl 请求地址

* @param requestMethod 请求方式(GET、POST)

* @param outputStr 提交的数据

* @return JSONObject(通过 JSONObject.get(key) 的方式获取 JSON 对象的属性值)

*/

public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {

JSONObject jsonObject = null;

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 conn = (HttpsURLConnection) url.openConnection();

conn.setSSLSocketFactory(ssf);

conn.setDoOutput(true);

conn.setDoInput(true);

conn.setUseCaches(false);

// 设置请求方式(GET/POST)

conn.setRequestMethod(requestMethod);

// 当 outputStr 不为 null 时,向输出流写数据

if (null != outputStr) {

OutputStream outputStream = conn.getOutputStream();

// 注意编码格式

outputStream.write(outputStr.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();

inputStream = null;

conn.disconnect();

jsonObject = JSONObject.fromObject(buffer.toString());

} catch (ConnectException ce) {

log.error(" 连接超时:{}", ce);

} catch (Exception e) {

log.error("https 请求异常:{}", e);

}

return jsonObject;

}

/**

* 获取接口访问凭证

*

* @param appid 凭证

* @param appsecret 密钥

* @return

*/

public static Token getToken(String appid, String appsecret) {

Token token = null;

String requestUrl = token_url.replace("APPID", appid).replace("APPSECRET", appsecret);

// 发起GET请求获取凭证

JSONObject jsonObject = httpsRequest(requestUrl, "GET", null);

if (null != jsonObject) {

try {

token = new Token();

token.setAccessToken(jsonObject.getString("access_token"));

token.setExpiresIn(jsonObject.getInt("expires_in"));

} catch (JSONException e) {

token = null;

// 获取token失败

log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));

}

}

return token;

}

/**

* URL编码(utf-8)

*

* @param source

* @return

*/

public static String urlEncodeUTF8(String source) {

String result = source;

try {

result = java.net.URLEncoder.encode(source, "utf-8");

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

}

return result;

}

/**

* 根据内容类型判断文件扩展名

*

* @param contentType 内容类型

* @return

*/

public static String getFileExt(String contentType) {

String fileExt = "";

if ("image/jpeg".equals(contentType))

fileExt = ".jpg";

else if ("audio/mpeg".equals(contentType))

fileExt = ".mp3";

else if ("audio/amr".equals(contentType))

fileExt = ".amr";

else if ("video/mp4".equals(contentType))

fileExt = ".mp4";

else if ("video/mpeg4".equals(contentType))

fileExt = ".mp4";

return fileExt;

}

}

#Token实体类具体代码:

/**

* 凭证实体类

*

* @author liufeng

*/

public class Token {

// 接口访问凭证

private String accessToken;

// 凭证有效期,单位:秒

private int expiresIn;

public String getAccessToken() {

return accessToken;

}

public void setAccessToken(String accessToken) {

this.accessToken = accessToken;

}

public int getExpiresIn() {

return expiresIn;

}

public void setExpiresIn(int expiresIn) {

this.expiresIn = expiresIn;

}

}

至此,我们获得了模板消息的access_token。将它作为参数传递到模板消息接口文档中POST请求的ACCESS_TOKEN。

//得到构造好的模板消息请求地址

String requestURL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="+access_token;


二、构造模板消息并发送

我们以一个餐饮行业的收到新订单通知的模板为例,模板详情如下:


模版消息

我的模板
模板库

返回上一层我的模板 /
模板详情

模板ID

YtO2XATY0VtRbgE4jWWNl-Zdc992FDdguhMUbomNkA0

开发者调用模板消息接口时需提供模板ID

标题收到新订单通知

行业餐饮 - 餐饮

详细内容

{{first.DATA}}

日期:{{Day.DATA}}
订单编号:{{orderId.DATA}}
订单类型:{{orderType.DATA}}
联系人:{{customerName.DATA}}
联系电话:{{customerPhone.DATA}}
{{remark.DATA}}

在发送时,需要将内容中的参数({{.DATA}}内为参数)赋值替换为需要的信息

内容示例
收到一个新的订单,确认接受请回复0,拒绝请回复1。

日期:2014-10-10
订单编号:1002
订单类型:订位
联系人:陈丑丑
联系电话:13222222222
订单金额:100.00元
付款状态:已微信支付

请及时处理您的订单。


按照上述条件,我们的消息体构造如下:

{"data":{"customerName":{"color":"#173177","value":"陈丑丑"},"customerPhone":{"color":"#173177","value":"13222222222"},"Day":{"color":"#173177","value":"15时06分"},"first":{"color":"#173177","value":"收到一个新的订单"},"orderId":{"color":"#173177","value":"1002"},"orderType":{"color":"#173177","value":"订位"},"remark":{"color":"#173177","value":"请及时处理您的订单"}},"template_id":"YtO2XATY0VtRbgE4jWWNl-Zdc992FDdguhMUbomNkA0","topcolor":"#173177","touser":"orsrOt9qBgO6dC-F3IL_MF52eplI","url":"http://weixin.qq.com/download"}

该消息体为一个json。具体封装如下:

/**

* 餐饮行业收到新订单通知模板消息实体类

* @author xjw

*

*/

public class NewOrdersTemplate {

private String touser; //用户OpenID

private String template_id; //模板消息ID

private String url; //URL置空,则在发送后,点击模板消息会进入一个空白页面(ios),或无法点击(android)。

private String topcolor; //标题颜色

private Data data; //详细内容

public String getTouser() {

return touser;

}

public void setTouser(String touser) {

this.touser = touser;

}

public String getTemplate_id() {

return template_id;

}

public void setTemplate_id(String templateId) {

template_id = 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 Data getData() {

return data;

}

public void setData(Data data) {

this.data = data;

}

}

/**

* "餐饮行业收到新订单通知"模板消息详细内容实体类

* @author xjw

*

*/

public class Data {

private Data_first first;

private Data_Day Day; //日期

private Data_orderId orderId; //订单编号

private Data_orderType orderType; //订单类型

private Data_customerName customerName; //联系人

private Data_customerPhone customerPhone; //联系电话

private Data_remark remark;

public Data_first getFirst() {

return first;

}

public void setFirst(Data_first first) {

this.first = first;

}

public Data_Day getDay() {

return Day;

}

public void setDay(Data_Day day) {

Day = day;

}

public Data_orderId getOrderId() {

return orderId;

}

public void setOrderId(Data_orderId orderId) {

this.orderId = orderId;

}

public Data_orderType getOrderType() {

return orderType;

}

public void setOrderType(Data_orderType orderType) {

this.orderType = orderType;

}

public Data_customerName getCustomerName() {

return customerName;

}

public void setCustomerName(Data_customerName customerName) {

this.customerName = customerName;

}

public Data_customerPhone getCustomerPhone() {

return customerPhone;

}

public void setCustomerPhone(Data_customerPhone customerPhone) {

this.customerPhone = customerPhone;

}

public Data_remark getRemark() {

return remark;

}

public void setRemark(Data_remark remark) {

this.remark = remark;

}

}

/**

* first

* @author xjw

*

*/

public class Data_first {

private String value;

private String color;

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;

}

}

/**

* 日期

* @author xjw

*

*/

public class Data_Day {

private String value;

private String color;

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;

}

}

/**

* 订单标号

* @author xjw

*

*/

public class Data_orderId {

private String value;

private String color;

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;

}

}

/**

* 订单类型

* @author xjw

*

*/

public class Data_orderType {

private String value;

private String color;

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;

}

}

/**

* 联系人

* @author xjw

*

*/

public class Data_customerName {

private String value;

private String color;

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;

}

}

/**

* 联系电话

* @author xjw

*

*/

public class Data_customerPhone {

private String value;

private String color;

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;

}

}

/**

* remark

* @author xjw

*

*/

public class Data_remark {

private String value;

private String color;

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;

}

}

/**

* 发送模板消息

* appId 公众账号的唯一标识

* appSecret 公众账号的密钥

* openId 用户标识

*/

public void send_template_message(String appId, String appSecret, String openId) {

Token token = CommonUtil.getToken(appId, appSecret);

String access_token = token.getAccessToken();

String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="+access_token;

NewOrdersTemplate temp = new NewOrdersTemplate();

Data data = new Data();

Data_first first = new Data_first();

Data_Day Day = new Data_Day();

Data_orderId orderId = new Data_orderId();

Data_orderType orderType = new Data_orderType();

Data_customerName customerName = new Data_customerName();

Data_customerPhone customerPhone = new Data_customerPhone();

Data_remark remark = new Data_remark();

first.setValue("收到一个新的订单");

first.setColor("#173177");

Day.setValue("14时56分");

Day.setColor("#173177");

orderId.setValue("1002");

orderId.setColor("#173177");

orderType.setValue("订位");

orderType.setColor("#173177");

customerName.setValue("陈丑丑");

customerName.setColor("#173177");

customerPhone.setValue("13222222222");

customerPhone.setColor("#173177");

remark.setValue("请及时处理您的订单");

remark.setColor("#173177");

data.setFirst(first);

data.setDay(Day);

data.setOrderId(orderId);

data.setOrderType(orderType);

data.setCustomerName(customerName);

data.setCustomerPhone(customerPhone);

data.setRemark(remark);

temp.setTouser(openId);

temp.setTemplate_id("YtO2XATY0VtRbgE4jWWNl-Zdc992FDdguhMUbomNkA0");

temp.setUrl("http://weixin.qq.com/download");

temp.setTopcolor("#173177");

temp.setData(data);

String jsonString = JSONObject.fromObject(temp).toString().replace("day", "Day");

JSONObject jsonObject = WeixinUtil.httpRequest(url, "POST", jsonString);

System.out.println(jsonObject);

int result = 0;

if (null != jsonObject) {

if (0 != jsonObject.getInt("errcode")) {

result = jsonObject.getInt("errcode");

log.error("错误 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));

}

}

log.info("模板消息发送结果:"+result);

}

WeixinUtil工具类在柳峰老师的博客里有源码。。。。。

实现效果如下:



如果小伙伴们觉得有什么问题可以提出,大家共同学习。

版权声明:本文为博主原创文章,未经博主允许不得转载。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: