Java微信公众号开发之接收消息+模板消息

本篇文章讲解了如何向用户发送模板消息,前提是已经搭建了微信开发环境。读完本文后,实现的主要效果如下

向已绑定用户发送模板消息,如我们常见的消费通知、订单通知等业务都可以用该功能实现。理论知识就不反复强调了,实践是检验真理的唯一标准,直接看例子,相信大家就能一目了然了。下面我们来看下要准备哪里步骤:

1.配置模板

登录测试公众号/正式公众号(认证后的服务号),测试公众号:模板消息接口->新增测试模板中添加模板,正式公众号:在功能->模板消息中添加模板,模板可以在模板库中选择,如果没有你需要的模板,可以申请添加,一个月可以申请三条。模板添加成功后,有个模板ID(用于接口调用)。

20190602更新:

很多人私信问,代码里面的模板是哪里来的。看上面,是微信后台配置的,模板内容和内容变量,会自动生成模板ID,在程序里面调用;变量要配置,值为程序里面传入的参数。

具体如何配置可以参看官方文档:https://mp.weixin.qq.com/wiki 中消息管理->发送消息-模板消息接口

2.代码应用展示

封装发送模板接口

package com.entry;

import java.util.Map;
/**
 * 模板基类
 * @author CLiang
 *
 */
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;
    }
}

一条模板包含多条数据,模板数据类封装

package com.entry;
/**
 * 模板数据
 * @author CLiang
 *
 */
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的请求接口:

package com.Servlet;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.Common.AccessTokenInfo;
import com.entry.AccessToken;
import com.util.NetWorkHelper;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;

/**
 * 用于获取accessToken的Servlet
 * Created by CLiang on 2018/8/14.
 */
@WebServlet(
        name = "AccessTokenServlet",
        urlPatterns = {"/AccessTokenServlet"},
        loadOnStartup = 1,
        initParams = {
                @WebInitParam(name = "appId", value = "wx2cf6086315216ab0"),
                @WebInitParam(name = "appSecret", value = "a4362add70c148da80e7442100782e4e")
        })
public class AccessTokenServlet extends HttpServlet {

    @Override
    public void init() throws ServletException {
        System.out.println("启动WebServlet");
        super.init();

        final String appId = getInitParameter("appId");
        final String appSecret = getInitParameter("appSecret");

        //开启一个新的线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        //获取accessToken
                        AccessTokenInfo.accessToken = getAccessToken(appId, appSecret);
                        //获取成功
                        if (AccessTokenInfo.accessToken != null) {
                            //获取到access_token 休眠7000秒,大约2个小时左右
                        	Thread.sleep(7000 * 1000);
                        	//Thread.sleep(10 * 1000);//10秒钟获取一次
                        } else {
                            //获取失败
                            Thread.sleep(1000 * 3); //获取的access_token为空 休眠3秒
                        }
                    } catch (Exception e) {
                        System.out.println("发生异常:" + e.getMessage());
                        e.printStackTrace();
                        try {
                            Thread.sleep(1000 * 10); //发生异常休眠1秒
                        } catch (Exception e1) {

                        }
                    }
                }

            }
        }).start();
    }

    /**
     * 获取access_token
     *
     * @return AccessToken
     */
    private AccessToken getAccessToken(String appId, String appSecret) {
        NetWorkHelper netHelper = new NetWorkHelper();
        /**
         * 接口地址为https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET,其中grant_type固定写为client_credential即可。
         */
        String Url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", appId, appSecret);
        //此请求为https的get请求,返回的数据格式为{"access_token":"ACCESS_TOKEN","expires_in":7200}
        String result = netHelper.getHttpsResponse(Url, "");
        System.out.println("获取到的access_token="+result);
        //使用FastJson将Json字符串解析成Json对象
        JSONObject json = JSON.parseObject(result);
        AccessToken token = new AccessToken();
        token.setAccessToken(json.getString("access_token"));
        token.setExpiresin(json.getInteger("expires_in"));
        return token;
    }
}

注意:ACCESS_TOKEN有请求次数限制,而且会在获取后7200秒后自动失效,所以要妥善保存好ACCESS_TOKEN,本实例是放在内存里面,每次获取时,判断是否已经存在,不存在才去请求,而如何保证保存的ACCESS_TOKEN为有效的呢?一般解决方法是定时请求获取最新ACCESS_TOKEN,更新内存里的数据,可使用servlet线程定时请求。

现在ACCESS_TOKEN已经获取,万事俱备,只欠调用了,下面给出发送模板

{{first.DATA}} 
订单编号:{{keyword1.DATA}} 
订单类型:{{keyword2.DATA}} 
商品名称:{{keyword3.DATA}} 
{{remark.DATA}}

这里是在测试公众号添加的模板,申请测试号网址http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login

    /**
     * 发送模板消息调用实例
     * @param map 封装了解析结果的Map
	 * @return 空 
     */
    private static String buildTempMessage(Map<String, String> map) {
    	//发送方帐号
        String fromUserName = map.get("FromUserName");
        // 开发者微信号
        String toUserName = map.get("ToUserName");
    	WxTemplate template = new WxTemplate();
    	template.setUrl("www.baidu.com");
    	template.setTouser(fromUserName);
    	template.setTopcolor("#000000");
    	template.setTemplate_id("EjM9IHXD5vD1oEBO0PuAcgLTG2-74d6mRdspS6XRh9o");
    	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("O00001");
    	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);
    	sendMessageBefore("",template, m);
    	return "";
    	
    }

上面的代码需要修改测试公众号生成的模板ID。 

    /**
     * 发送模板消息前获取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;
        token = AccessTokenInfo.accessToken;
//        if(template_id_short!=null&&!"".equals(template_id_short)){
//            WxTemplate template = WeixinUtil.getTemplate(template_id_short,token.getToken());
//            t.setTemplate_id(template.getTemplate_id());
//        }
        t.setData(m);
        sendMessage(t,token.getAccessToken());
    }
    /**
     * 发送模板消息
     * @param t
     * @param accessToken
     * @return
     */
    public static int sendMessage(WxTemplate t,String accessToken) {
        int result = 0;
        // 拼装创建菜单的url
        String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN".replace("ACCESS_TOKEN", accessToken);
        // 将菜单对象转换成json字符串
        String jsonMenu = JSONObject.toJSONString(t);
        // 调用接口创建菜单
        String response = WeChatApiUtil.httpsRequestToString(url, "POST", jsonMenu);
        JSONObject jsonObject = JSON.parseObject(response);
        //JSONObject jsonObject = httpRequest(url, "POST", jsonMenu);
        if (null != jsonObject) {
            if (0 != jsonObject.getIntValue("errcode")) {
                result = jsonObject.getIntValue("errcode");
                System.out.println("发送模板消息失败 errcode:{"
                +jsonObject.getIntValue("errcode")+"} errmsg:{"+jsonObject.getString("errmsg")+"}");
            }
        }
        return result;
    }

至此,发送消息流程已全部完成。向测试公众号发送“模板”后,微信返回的模板显示效果如下

所有源代码、请参考 https://download.csdn.net/download/u011752195/10604165

如有不足、不解或者改进之处,欢迎大家在评论区指出,相互交流。

整个下来通过网络资源整理学习,并且完善了一些代码,程序员挺累的

如果觉得不错可以点歌关注吧~

后续将分享更多程序代码~

合作请联系chat 1012638162

有问题可以在下面提出来~

如果本文对您有一丢丢帮助,可以通过下方二维码支持作者哦 后续将分享更多高质量代码~

        Alipay                    WeChat

      

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值