zoukankan      html  css  js  c++  java
  • 微信公众号开发《二》发送模板消息实现消息业务实时通知

    原创声明:本文为原创作品,绝非他处摘取,转载请联系博主

    前篇文章讲解了如何获取用户微信基本详情,实现微信绑定后自动登录,回看请点击这里: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

    至此,发送消息流程已全部完成,如有不足,不解或者改进之处,欢迎大家在评论区指出。

  • 相关阅读:
    javascript 基础知识-1
    AngularJs-指令和指令之间的交互(动感超人)
    AngularJs-指令和控制器交互
    奇点大学公开课之尼葛洛庞帝讲述物联网和智能设备
    AngularJs-数据绑定
    AngularJs-指令1
    AngularJs-MVC之路由、模块以及依赖注入
    AngularJS-MVC
    利用canvas制作图片(可缩放和平移)+相框+文字
    Django rest framework 认证组件源码分析
  • 原文地址:https://www.cnblogs.com/zhaixiajiao/p/6743686.html
Copyright © 2011-2022 走看看