原創聲明:本文為原創作品,絕非他處摘取,轉載請聯系博主
前篇文章講解了如何獲取用戶微信基本詳情,實現微信綁定后自動登錄,回看請點擊這里:http://www.cnblogs.com/zhaixiajiao/p/6760194.html
本篇文章主要介紹利用上篇文章獲取到的微信ID,向已綁定用戶發送模板消息,如我們常見的消費通知、訂單通知等業務都可以用該功能實現。理論知識就不反復強調了,實踐是檢驗真理的唯一標准,直接看例子,相信大家就能一目了然了。下面我們來看下要准備哪里步驟:
1.配置模板
登錄測試公眾號/正式公眾號(認證后的服務號),測試公眾號:模板消息接口->新增測試模板中添加模板,正式公眾號:在功能->模板消息中添加模板,模板可以在模板庫中選擇,如果沒有你需要的模板,可以申請添加,一個月可以申請三條。模板添加成功后,有個模板ID(用於接口調用)。
具體如何配置可以參看官方文檔:https://mp.weixin.qq.com/wiki 中消息管理->發送消息-模板消息接口
2.代碼應用展示
封裝發送模板接口
import java.util.Map; /** * 模板基類 * @author lh * */ public class WxTemplate { private String template_id;//模板ID private String touser;//目標客戶 private String url;//用戶點擊模板信息的跳轉頁面 private String topcolor;//字體顏色 private Map<String,TemplateData> data;//模板里的數據 public String getTemplate_id() { return template_id; } public void setTemplate_id(String template_id) { this.template_id = template_id; } public String getTouser() { return touser; } public void setTouser(String touser) { this.touser = touser; } 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 Map<String,TemplateData> getData() { return data; } public void setData(Map<String,TemplateData> data) { this.data = data; } }
一條模板包含多條數據,模板數據類封裝
/** * 模板數據 * @author lh * */ public class TemplateData { 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; } }
看文檔,發送模板信息接口為:https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN,前期模板數據都准備好了,現在缺少ACCESS_TOKEN,缺什么就去獲取什么,查看文檔可知獲取ACCESS_TOKEN接口為:https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET,現在就封裝個獲取ACCESS_TOKEN的請求接口:
public class WeixinUtil { private static Logger log = LoggerFactory.getLogger(WeixinUtil.class); // 獲取access_token的接口地址(GET) 限200(次/天) public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"; /** * 獲取access_token * @param appid 憑證 * @param appsecret 密鑰 * @return */ public static AccessToken getAccessToken(String appid, String appsecret) { AccessToken accessToken = null; String requestUrl = access_token_url.replace("APPID", appid).replace("APPSECRET", appsecret); JSONObject jsonObject = httpRequest(requestUrl, "GET", null); // 如果請求成功 if (null != jsonObject) { try { accessToken = new AccessToken(); accessToken.setToken(jsonObject.getString("access_token")); accessToken.setExpiresIn(jsonObject.getInt("expires_in")); } catch (JSONException e) { accessToken = null; // 獲取token失敗 log.error("獲取token失敗 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg")); } } return accessToken; } }
注意:ACCESS_TOKEN有請求次數限制,而且會在獲取后7200秒后自動失效,所以要妥善保存好ACCESS_TOKEN,本實例是放在內存里面,每次獲取時,判斷是否已經存在,不存在才去請求,而如何保證保存的ACCESS_TOKEN為有效的呢?一般解決方法是定時請求獲取最新ACCESS_TOKEN,更新內存里的數據,可使用線程定時請求、quartz,或者Spring的任務調度功能,下面展示比較通用的線程方法:
/** * 定時獲取微信access_token的線程 */ public class TokenThread implements Runnable { private static Logger log = LoggerFactory.getLogger(TokenThread.class); // 第三方用戶唯一憑證 public static String appid = "xxx"; // 第三方用戶唯一憑證密鑰 public static String appsecret = "xxxx"; public static AccessToken accessToken = null;//保存ACCESS_TOKEN到內存 public void run() { while (true) { try { accessToken = WeixinUtil.getAccessToken(appid, appsecret); if(null != accessToken) { log.info("獲取access_token成功,有效時長{}秒 token:{}", accessToken.getExpiresIn(), accessToken.getToken()); // 休眠7000秒 Thread.sleep((accessToken.getExpiresIn() - 200) * 1000); }else{ // 如果access_token為null,60秒后再獲取 Thread.sleep(60 * 1000); } } catch (InterruptedException e) { try{ Thread.sleep(60 * 1000); } catch (InterruptedException e1) { log.error("{}", e1); } log.error("{}", e); } } } }
現在ACCESS_TOKEN已經獲取,萬事俱備,只欠調用了,下面給出發送模板
{{first.DATA}} 訂單編號:{{keyword1.DATA}} 訂單類型:{{keyword2.DATA}} 商品名稱:{{keyword3.DATA}} {{remark.DATA}}
的具體調用實例:
/** * 發送模板消息調用實例 * @param websiteAndProject 請求地址與工程名:http://192.168.2.113/seafood * @param receiverWeixinId 接受者的微信ID,如何獲取,可看前一篇文章 * @return */ WxTemplate template = new WxTemplate(); template.setUrl(""+TimedTask.websiteAndProject+"/weixinTwo/gotoOrderConfirm?orderId="+map.get("orderId")); template.setTouser("receiverWeixinId")); template.setTopcolor("#000000"); template.setTemplate_id("ai3WcdUjq-x4v0Reir442UCIzl3AsyCgpAy0e5q2mkY"); Map<String,TemplateData> m = new HashMap<String,TemplateData>(); TemplateData first = new TemplateData(); first.setColor("#000000"); first.setValue("您好,您有一條待確認訂單。"); m.put("first", first); TemplateData keyword1 = new TemplateData(); keyword1.setColor("#328392"); keyword1.setValue("OD0001"); m.put("keyword1", keyword1); TemplateData keyword2 = new TemplateData(); keyword2.setColor("#328392"); keyword2.setValue("預定訂單"); m.put("keyword2", keyword2); TemplateData keyword3 = new TemplateData(); keyword3.setColor("#328392"); keyword3.setValue("大龍蝦"); m.put("keyword3", keyword3); TemplateData remark = new TemplateData(); remark.setColor("#929232"); remark.setValue("請及時確認訂單!"); m.put("remark", remark); WeixinUtil.sendMessageBefore("",template, m);
public class WeixinUtil { private static Logger log = LoggerFactory.getLogger(WeixinUtil.class); // 獲取access_token的接口地址(GET) 限200(次/天) public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"; /** * 獲取access_token * @param appid 憑證 * @param appsecret 密鑰 * @return */ public static AccessToken getAccessToken(String appid, String appsecret) { AccessToken accessToken = null; String requestUrl = access_token_url.replace("APPID", appid).replace("APPSECRET", appsecret); JSONObject jsonObject = httpRequest(requestUrl, "GET", null); // 如果請求成功 if (null != jsonObject) { try { accessToken = new AccessToken(); accessToken.setToken(jsonObject.getString("access_token")); accessToken.setExpiresIn(jsonObject.getInt("expires_in")); } catch (JSONException e) { accessToken = null; // 獲取token失敗 log.error("獲取token失敗 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg")); } } return accessToken; } /** * 發送模板消息前獲取token * @param template_id_short 模板庫中模板的編號 * @param t * @param m */ public static void sendMessageBefore(String template_id_short,WxTemplate t,Map<String,TemplateData> m){ AccessToken token = null; if(TokenThread.accessToken==null || TokenThread.accessToken.getToken()==""){ token = WeixinUtil.getAccessToken(TokenThread.appid, TokenThread.appsecret); }else{ token = TokenThread.accessToken; } if(template_id_short!=null&&!"".equals(template_id_short)){ Template template = WeixinUtil.getTemplate(template_id_short,token.getToken()); t.setTemplate_id(template.getTemplate_id()); } t.setData(m); int result = WeixinUtil.sendMessage(t,token.getToken()); } /** * 發送模板消息 * @param t * @param accessToken * @return */ public static int sendMessage(WxTemplate t,String accessToken) { int result = 0; // 拼裝創建菜單的url String url = sendTemplateMessage_url.replace("ACCESS_TOKEN", accessToken); // 將菜單對象轉換成json字符串 String jsonMenu = JSONObject.fromObject(t).toString(); // 調用接口創建菜單 JSONObject jsonObject = httpRequest(url, "POST", jsonMenu); if (null != jsonObject) { if (0 != jsonObject.getInt("errcode")) { result = jsonObject.getInt("errcode"); log.error("發送模板消息失敗 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg")); } } return result; } }
本人另一博客【http://blog.csdn.net/liaohaojian/article/details/70225367】
至此,發送消息流程已全部完成,如有不足,不解或者改進之處,歡迎大家在評論區指出。