任务描述
原本的消息推送分为两个类型,文本消息和图文消息。现在要将其中一部分修改为图文消息。参考:
准备工作
首先应该去微信的官方客服购买消息模板,购买以后会获得template_id_short,即模板库中模板的编号,有“TM**”和“OPENTMTM**”等形式。并且会有对应的模板样式,如下:
{ {first.DATA}}订单号:{ {keyword1.DATA}}商品名称:{ {keyword2.DATA}}收件人姓名:{ {keyword3.DATA}}收件人电话:{ {keyword4.DATA}}收件人地址:{ {keyword5.DATA}}{ {remark.DATA}}您提交的发货订单已发货订单号:5244030005646商品名称:某商品收件人姓名:陈璐收件人电话:13522211111收件人地址:广东省 广州市 天河区 科韵北路112号如有疑问,请尽快联系我们。
注意事项
- 模板中的关键字,必须与模板保持一致,否则模板并不会识别。如:{ {first.DATA}},最后保存JSON 的时候,名字应为{"first",first}. 2.申请模板之后,模板的存储数量有限,所以需要写方法,将已经获取的模板id(template_id)存放在缓存或者数据库中,下一次以同样的appid和template_id_short去获取template_id时,先判断是否已经在缓存或数据库中存在,若不存在,再去获取。 3.微信中可以存放的模板id数量有限,所以需要方法去判断之前是否申请过模板id,保证模板id不会重复被申请。 4.如果模板出现错误,应该删除更新。 5.如果出现错误,去官方文档中可以查询到错误原因。 /暂时想到的就这么多,如果还有其他,欢迎补充/
###1. 获取access_token的方法
@Componentpublic class WxCacheManager extends CacheManager{ @Autowired private JedisManager manager; @Override public int getDbIndex() { return IConstants.DB_INDEX_VARIABLE; } @Override public JedisManager getJedisManager() { return manager; } /** * 获取指定公众号的access_token * @param appid 公众号的appid * @return */ public String getTokenFromCache(String appid){ String access_token = (String)this.getByKey("access_token_" + appid); if(Commons.isNull(access_token)){ String appsecret = WeixinUtil.getAppsecret(appid); AccessToken accessToken = WeixinUtil.getAccessToken(appid, appsecret); access_token = accessToken.getToken(); if(!Commons.isNull(access_token)){ this.setKeyValue("access_token_" + appid,access_token,7000); } } return access_token; } /** * 获得指定公众号的jsApiTicket * @param appid 公众号的appid * @return */ public String getJsApiTicketFromCache(String appid){ String jsApiTicket = (String)this.getByKey("jsApiTicket_" + appid); if(Commons.isNull(jsApiTicket)){ JsApiTicket jsTicket = WeixinUtil.getJsTicket(getTokenFromCache(appid)); jsApiTicket = jsTicket.getTicket(); if(!Commons.isNull(jsApiTicket)){ this.setKeyValue("jsApiTicket_" + appid,jsApiTicket,7000); } } return jsApiTicket; } /** * 从缓存中查询微信用户信息 * @param appid * @param openid * @return */ public UserInfo getUserInfoFromCache(String appid, String openid){ UserInfo userinfo = (UserInfo)super.getByKey("userinfo_" + appid + "_" + openid); if(Commons.isNull(userinfo)){ userinfo = WeixinUtil.getUserInfoByOpenid(this.getTokenFromCache(appid),openid); if(userinfo!=null){ super.setKeyValue("userinfo_" + appid + "_" + openid,userinfo,3600); } } return userinfo; } /** * 将微信用户信息添加到缓存 * @param userinfo * @param appid */ public void setUserInfoCache(UserInfo userinfo, String appid){ if(!Commons.isNull(userinfo) && !Commons.isNull(userinfo.getOpenid()) && !Commons.isNull(appid)){ this.setKeyValue("userinfo_" + appid + "_" + userinfo.getOpenid(),userinfo,3600); } } /** * 从缓存中获取指定公众号信息 * @param appid * @return */ public Wbapp getWbappFromCache(String appid){ return null; /*return (Wbapp)this.getByKey("wbapp_" + appid);*/ } /** * 将公众号信息添加到缓存 * @param wbapp */ public void setWbappCache(Wbapp wbapp){ if(!Commons.isNull(wbapp)){ this.setKeyValue("wbapp_" + wbapp.getAppid(),wbapp,7000); } } /** * 从缓存中查询用户基本信息 * @param id * @return */ public WbUser getWbUserFromCache(Long id){ return null; //return (WbUser)super.getByKey(WbUser.class.getCanonicalName() + id); } /** * 将用户基本信息添加到缓存 * @param wbuser */ public void setWbUserCache(WbUser wbuser){ if(!Commons.isNull(wbuser)){ this.setKeyValue(WbUser.class.getCanonicalName() + wbuser.getId(),wbuser,7000); } } public Long getSyncTimesFromCache(String appid){ return (Long)this.getByKey("wzc_synctimes_" + appid); } public void setSyncTimesCache(String appid,Long time){ if(!Commons.isNull(appid) && !Commons.isNull(time)){ this.setKeyValue("wzc_synctimes_" + appid,time,24*60*60); } }}
2. 模板消息类
public class WxTemplate { private String template_id; private String touser; private String url; private String topcolor; private Mapdata; 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 getData() { return data; } public void setData(Map data) { this.data = data; }}
3.设置每条模板消息信息的类
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; } }
4.模板消息使用方法部分
//消息类型@Servicepublic class MessageUtil { /** * 发送模板消息 * @param appid * @param openid * @param template_id 模板id * @param data 模板消息内容 * @param url URL置空,则在发送后,点击模板消息会进入一个空白页面(ios),或无法点击 */ public static void sendTemplateMessage(String appid, String openid, String template_id, Mapdata, String url, String template_id_short){ WxCacheManager wxCacheManager = SpringContextHolder.getBean(WxCacheManager.class); WxTemplate wxTemplate = new WxTemplate(); wxTemplate.setTouser(openid); wxTemplate.setTemplate_id(template_id); //微信端页面是否有跳转,通过判断跳转链接是否为空来决定,所以当url为空时,将链接设置为"" if (url==null){ wxTemplate.setUrl(""); }else { wxTemplate.setUrl(url); } wxTemplate.setData(data); String access_token = wxCacheManager.getTokenFromCache(appid); String request_url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + access_token; JSONObject returnObj = com.xiangshi.wzc.wx.util.MessageUtil.httpRequest(request_url, "POST", JSONObject.fromObject(wxTemplate).toString()); if(returnObj.containsKey("errcode") && "40037".equals(returnObj.getString("errcode"))) { ActiveMQQueue dest = new ActiveMQQueue("Wzc_template_List"); long delayTime = TimingConstants.DELAY_TIME_TWO_SECOND; Map map = new HashMap (); map.put("appid", appid); map.put("openid", openid); map.put("template_id", template_id); map.put("data", data); map.put("url", url); map.put("template_id_short", template_id_short); JSONObject jsonObject = JSONObject.fromObject(map); SendMessage sendMessage = SpringContextHolder.getBean(SendMessage.class); sendMessage.sendSingle(jsonObject.toString(), dest, delayTime); } } /** * 获取模板id * @param appid * @param template_id_short 模板库中模板的编号 * @return */ public static String applyTemplateID(String appid,String template_id_short){ WxCacheManager wxCacheManager = SpringContextHolder.getBean(WxCacheManager.class); String access_token = wxCacheManager.getTokenFromCache(appid); String request_url = "https://api.weixin.qq.com/cgi-bin/template/api_add_template?access_token=" + access_token; Map map = new HashMap (); map.put("template_id_short",template_id_short); JSONObject resultObj = com.xiangshi.wzc.wx.util.MessageUtil.httpRequest(request_url, "POST", JSONObject.fromObject(map).toString()); if (resultObj.containsValue("ok")){ return String.valueOf(resultObj.get("template_id")); }else { return null; } } /** * 获取模板列表 * @param appid * @return */ public static JSONArray getTemplateList(String appid) { WxCacheManager wxCacheManager = SpringContextHolder.getBean(WxCacheManager.class); String access_token = wxCacheManager.getTokenFromCache(appid); String request_url = "https://api.weixin.qq.com/cgi-bin/template/get_all_private_template?access_token=" + access_token; JSONObject resultObj = com.xiangshi.wzc.wx.util.MessageUtil.httpRequest(request_url, "GET", null); if(resultObj.containsKey("template_list")) { return resultObj.getJSONArray("template_list"); } else { return null; } } /** * 根据模板id删除模板 * @param appid * @param template_id */ public static void deleteTemplateById(String appid, String template_id) { WxCacheManager wxCacheManager = SpringContextHolder.getBean(WxCacheManager.class); String access_token = wxCacheManager.getTokenFromCache(appid); String request_url = "https://api.weixin.qq.com/cgi-bin/template/del_private_template?access_token=" + access_token; Map map = new HashMap (); map.put("template_id", template_id); com.xiangshi.wzc.wx.util.MessageUtil.httpRequest(request_url, "POST", JSONObject.fromObject(map).toString()); } public static void main(String[] args){ }}
5.获取模板id的时候,判断模板是否已经存在,更新模板id
@Servicepublic class MessageWxTemplateServiceImpl extends BaseServiceImplimplements MessageWxTemplateService { @Autowired private MessageWxTemplateDao messageWxTemplateDao; @Autowired private WxCacheManager cacheManager; private static final String CACHE_PREFIX = "WXTemplateID_"; private static final Integer TIME_ONE_DAY_SECOND = 24 * 60 * 60; @Override protected BaseDao getBaseDao() { return messageWxTemplateDao; } @Override public String getApplyTemplateID(String appid, String template_id_short){ String templateid = (String) cacheManager.getByKey(CACHE_PREFIX+appid+"_"+template_id_short); if(templateid==null){ MessageWxTemplate messageWxTemplate = new MessageWxTemplate(); messageWxTemplate.setTemplate_id_short(template_id_short); messageWxTemplate.setAppid(appid); messageWxTemplate = messageWxTemplateDao.selectOne(messageWxTemplate); if(messageWxTemplate==null){ templateid = MessageUtil.applyTemplateID(appid,template_id_short); messageWxTemplate = new MessageWxTemplate(); messageWxTemplate.setTemplate_id_short(template_id_short); messageWxTemplate.setAppid(appid); messageWxTemplate.setTemplate_id(templateid); this.insert(messageWxTemplate); return templateid; } else { setTemplateCache(messageWxTemplate); return messageWxTemplate.getTemplate_id(); } } else { return templateid; } } @Override public String updateTemplateID(String appid, String template_id, String template_id_short) { //1-1.获取模板编号在数据库中对应的信息 MessageWxTemplate query = new MessageWxTemplate(); query = new MessageWxTemplate(); query.setAppid(appid); query.setTemplate_id_short(template_id_short); MessageWxTemplate template = messageWxTemplateDao.selectOne(query); if (!Commons.isNull(template)) { //1-2.清除缓存中数据 delTemplateCache(appid, template_id_short); //1-3.将此错误模板信息从数据库删除 messageWxTemplateDao.deleteById(template.getId()); } //1-4.获取数据库中平台所有的模板信息 query = new MessageWxTemplate(); query.setAppid(appid); List templates = messageWxTemplateDao.selectList(query); //2.获取微信中平台所有的模板信息 JSONArray templatesWX = MessageUtil.getTemplateList(appid); //3.比对,将错误的模板删掉(删掉的是所有的错误模板) boolean next = true; if (!Commons.isNull(templates) && templates.size() > 0 && !Commons.isNull(templatesWX) && templatesWX.size() > 0 ) { for (int i = 0; i < templatesWX.size(); i++) { JSONObject templateInfo = templatesWX.getJSONObject(i); //表示此模板是否需要删除,默认需要删除 boolean b = true; if (templateInfo.containsKey("template_id")) { //3-1.循环比较微信中的模板是否也在数据库中 for (MessageWxTemplate mwt : templates) { //3-1-1.此模板存在,不需要删除 if (templateInfo.getString("template_id").equals(mwt.getTemplate_id())) { b = true; break; } } if (!b) { //3-1-2.此模板存在,需要删除 MessageUtil.deleteTemplateById(appid, templateInfo.getString("template_id")); } } } } else if ((Commons.isNull(templates) || templates.size() == 0) && !Commons.isNull(templatesWX) && templatesWX.size() > 0 ) { for (int i = 0; i < templatesWX.size(); i++) { JSONObject templateInfo = templatesWX.getJSONObject(i); if (templateInfo.containsKey("template_id")) { MessageUtil.deleteTemplateById(appid, templateInfo.getString("template_id")); } } } //5.根据template_id_short获取新的template_id String new_template_id = MessageUtil.applyTemplateID(appid, template_id_short); if (Commons.isNull(new_template_id)) { return null; } return new_template_id; } @Override public void insert(MessageWxTemplate entity) { if(entity==null||entity.getTemplate_id_short()==null||entity.getAppid()==null||entity.getTemplate_id()==null){ return; } super.insert(entity); setTemplateCache(entity); } private void setTemplateCache(MessageWxTemplate entity){ cacheManager.setKeyValue(CACHE_PREFIX+entity.getAppid()+"_"+entity.getTemplate_id_short(), entity.getTemplate_id(), TIME_ONE_DAY_SECOND); } private void delTemplateCache(String appid, String template_id_short){ cacheManager.deleteByKey(CACHE_PREFIX+appid+"_"+template_id_short); }}
6.发送模板消息
//获取模板id String template_id = messageWxTemplateService.getApplyTemplateID(appid,"OPENTM*********"); if (template_id!=null||template_id!="") { messages.setMsgtype("模板通知"); //修改为模板消息 //{ {first.DATA}} TemplateData first = new TemplateData(); first.setValue("您提交的发货订单已发货"); first.setColor("#173177 "); //订单内容:{ {keyword1.DATA}} TemplateData keyword1 = new TemplateData(); keyword1.setValue(order.getProname()); keyword1.setColor("#173177 "); //物流服务:{ {keyword2.DATA}} TemplateData keyword2 = new TemplateData(); keyword2.setValue(deliverOrder.getExpress()); keyword2.setColor("#173177 "); //快递单号:{ {keyword3.DATA}} TemplateData keyword3 = new TemplateData(); keyword3.setValue(deliverOrder.getExpressno()); keyword3.setColor("#173177 "); //收货信息:{ {keyword4.DATA}} TemplateData keyword4 = new TemplateData(); StringBuffer receiveMessage = new StringBuffer(); receiveMessage.append(deliverOrder1.getConsignee()); receiveMessage.append(" "); receiveMessage.append(deliverOrder1.getConsigneemobile()); receiveMessage.append(" "); receiveMessage.append(deliverOrder1.getP_c_d()); receiveMessage.append(" "); receiveMessage.append(deliverOrder1.getAddress()); keyword4.setValue(receiveMessage.toString()); keyword4.setColor("#173177 "); //{ {remark.DATA}} TemplateData remark = new TemplateData(); remark.setValue("\n如有疑问,请尽快联系我们。"); remark.setColor("#173177 "); Mapdata = new HashMap<>(); data.put("first", first); data.put("keyword1", keyword1); data.put("keyword2", keyword2); data.put("keyword3", keyword3); data.put("keyword4", keyword4); data.put("remark", remark); MessageUtil.sendTemplateMessage(appid, wbUser1.getOpenid(), template_id, data, Commons.getClientServer() + "/wzc/order/" + order.getId() + "?state=" + appid, "OPENTM************");
最后的话
本来写工作日志是不打算公开的,毕竟觉得自己看看就好了,但是之前有人跟我说,公开之后,让别人看到,有人指出不足,会更好,所以还是公开好了~"OPENTM************"然后这一部分是被我手动注释掉了。写东西完全按照自己的思维来,比较乱。就是这样。