微信接口文档:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/template-message.html
调用微信服务消息的请求接口为:https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=ACCESS_TOKEN
还有一个地址为微信公众号的消息推送接口:https://api.weixin.qq.com/cgi-bin/template/api_set_industry?access_token=ACCESS_TOKEN
这里用服务消息的接口而不是公众号消息推送的接口,公众号接口需要付费开通权限
关于服务推送form_id问题:
- form_id有时效性,网上有说7天,但文档中没有维护。
- form_id用过一次就失效。
- form_id要真机提供才有效
1.模板实体类
public class TemplateData {
private String value;
//color在服务消息通知中废弃,但在公众号消息通知仍存在
private String color;
public TemplateData(String value,String color){
this.value = value;
this.color = color;
}
//get set 省略
}
public class TemplateMessage {
/** 接收者openid */
private String touser;
/** 所需下发的模板消息的id */
private String templateId;
/**小程序要跳转的页面url*/
private String page;
/**
* 表单提交场景下,为 submit 事件带上的 formId;支付场景下,为本次支付的 prepay_id
* */
private String formId;
/** 模板数据 */
private Map<String,TemplateData> data;
/** 模板需要放大的关键词,不填则默认无放大 */
private String emphasiseyword;
//get set 省略
}
2.获取token
public class AccessTokenRequestHandler extends RequestHandler {
public AccessTokenRequestHandler(HttpServletRequest request,
HttpServletResponse response) {
super(request, response);
}
private static String access_token = "";
/**
* 获取小程序凭证access_token
* @return
*/
public static String getMinAccessToken() {
if ("".equals(access_token)) {// 如果为空直接获取
return getMinTokenReal();
}
if (tokenIsExpire(access_token)) {// 如果过期重新获取
return getMinTokenReal();
}
return access_token;
}
/**
* 实际获取小程序access_token的方法
* @return
*/
protected static String getMinTokenReal() {
//获取token所需参数url,grant_type,appid,appsecret用自己的
String requestUrl = TOKENURL + "?grant_type=" +GRANT_TYPE + "&appid="
+ APPID + "&secret=" + APPSECRET;
String resContent = "";
TenpayHttpClient httpClient = new TenpayHttpClient();
httpClient.setMethod("GET");
httpClient.setReqContent(requestUrl);
if (httpClient.call()) {
resContent = httpClient.getResContent();
if (resContent.indexOf(ConstantUtil.ACCESS_TOKEN) > 0) {
access_token = JsonUtil.getJsonValue(resContent, ConstantUtil.ACCESS_TOKEN);
} else {
System.out.println("获取access_token值返回错误!!!");
}
} else {
System.out.println("后台调用通信失败");
System.out.println(httpClient.getResponseCode());
System.out.println(httpClient.getErrInfo());
// 有可能因为网络原因,请求已经处理,但未收到应答。
}
return access_token;
}
}
3.发起https请求并获取结果
public class WeixinUtil {
private static Logger log = LoggerFactory.getLogger(WeixinUtil.class);
/**
* 发起https请求并获取结果
*
* @param requestUrl 请求地址
* @param requestMethod 请求方式(GET、POST)
* @param outputStr 提交的数据
* @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
*/
public static String httpRequest(String requestUrl, String requestMethod, String outputStr) {
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();
} catch (ConnectException ce) {
log.error("Weixin server connection timed out.");
} catch (Exception e) {
log.error("https request error:{}", e);
}
return buffer.toString();
}
}
4.发送
public class WXMsgRun {
public static TemplateMessage TemplateMessage(String opinid, String pagepath, String formId,
Map<String, TemplateData> data, String emphasiseyword) {
TemplateMessage templateMessage = new TemplateMessage();
templateMessage.setTouser(opinid);
templateMessage.setPagepath(pagepath);
templateMessage.setFormId(formId);
templateMessage.setData(data);
templateMessage.setEmphasiseyword(emphasiseyword);
return templateMessage;
}
/**
*
*/
public static void sendOrderPayMessage(String... 相关模板字段的值自己配) {
Map<String, TemplateData> data = new HashMap<String, TemplateData>();
data.put("keyword1", new TemplateData(xxxxx, null));
data.put("keyword2", new TemplateData(yyyyy, null));
sendMessage(opinid, page, data, formId, null);
}
/**
*
* @param opinid 被推送用户的openid
* @param page 消息推送后小程序跳转的页面路径
* @param data 封装的主体数据
* @param formId 小程序提交的表单id
* @param emphasiseyword 需要强调的关键字段 格式为 "keyword1.DATA"
*/
public static void sendMessage(String opinid,String page,
Map<String, TemplateData> data, String formId, String emphasiseyword) {
sendWechatMsgToUser(opinid, page, formId, data, emphasiseyword);
}
private static void sendWechatMsgToUser(TemplateMessage templateMessage) {
WXSendMsgJob job = new WXSendMsgJob(TemplateMessage);
//我的方法用线程处理,也可不用,只是个demo
ThreadPoolManager.getInstance().addExecuteTask(job);
}
}
public class WXMessageUtil {
private static Logger log = LoggerFactory.getLogger(WXMessageUtil.class);
public static JSONObject dataJsonmsg(Map<String, TemplateData> data) {
JSONObject json = new JSONObject();
for (Map.Entry<String,TemplateData> entry : data.entrySet()) {
JSONObject keyJson = new JSONObject();
TemplateData dta= entry.getValue();
keyJson.put("value",dta.getValue());
keyJson.put("color", dta.getColor());
json.put(entry.getKey(), keyJson);
}
return json;
}
/**
* 发送微信消息(模板消息)
*
* @param touser 用户 OpenID
* @param templatId 模板消息ID
* @return
*/
public static JSONObject sendWechatMsgToUser(String touser, String templatId, String page, String formId,
Map<String, TemplateData> data, String emphasiseyword) {
// String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="
// + AccessTokenRequestHandler.getAccessToken();
String url = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token="
+ AccessTokenRequestHandler.getMinAccessToken();
JSONObject json = new JSONObject();
JSONObject jsonDataMsg = dataJsonmsg(data);
json.put("touser", touser);
json.put("template_id", templatId);
json.put("page", page);
json.put("form_id", formId);
json.put("data", jsonDataMsg);
json.put("emphasis_keyword", emphasiseyword);
System.out.println("post数据包"+json.toString());
JSONObject parseObject = null;
try {
String requestMethod = "POST";
String result = WeixinUtil.httpRequest(url, requestMethod, json.toString());
parseObject = JSON.parseObject(result);
log.info("发送微信消息返回信息:" + parseObject);
log.info("发送微信消息返回信息编码:" + parseObject.get("errcode"));
String errmsg = (String) parseObject.get("errmsg");
log.info("获取模板编号返回信息:" + errmsg);
if (!"ok".equals(errmsg)) { // 如果为errmsg为ok,则代表发送成功
log.info("失败信息" + parseObject.toJSONString());
//失败处理
}
} catch (Exception e) {
e.printStackTrace();
}
return parseObject;
}
}