微信公众号开发之发送模板消息

在我们做微信公众号开发时,发送模板消息往往是必不可少的功能。今天我们就来说说吧!

1、申请模板消息

首先我们应该知道,模板消息是需要申请的。这个申请就其本身来说是很easy的(我前一天晚上申请的,显示需要2--3个工作日,结果第二天早上就发现已经开通了,所以说腾讯官方还是比较给力的哈)。
但是我们在申请时还是有一些东西要注意,这个在官方的文档有非常详细的说明。

这个我建议你好好看看。选择行业的时候可要谨慎些,因为这个一个月只可以修改一次。
那么,我们来看看在哪里申请?


微信公众号开发之发送模板消息_第1张图片

这里我已经申请过了。
申请之后就耐心等待,审核通过之后再功能这一栏里就会出现模板消息的菜单。你可以看看我上面的截图,就在第三项。

2、添加模板消息

审核通过之后,我们就可以添加模板消息,进行开发了。

这个很简单:


微信公众号开发之发送模板消息_第2张图片

我们点击模板消息进入后,直接在模板库中选择你需要的消息模板添加就可以了,添加之后就会在我的模板中。会有一个模板id,这个模板id在我们发送消息的时候会用到。


微信公众号开发之发送模板消息_第3张图片

3、消息发送功能开发

接下来我们就看看如何发送模板消息:

这个是官方文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277

我呢,也来说说我的实现吧。为了更方便,我会直接将相关代码贴出来。

文档中我们可以看到接口地址如下:

http请求方式: POST
https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN

这里我们首先需要的就是access_token了,这个在这里就不多说了。通过你的appid和secret就可以获取。

【获取access_token : https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183】

关于相关参数,我直接就将官方文档贴来了(文档写的很清楚):
POST数据示例如下:

{
           "touser":"OPENID",
           "template_id":"ngqIpbwh8bUfcSsECmogfXcV14J0tQlEpBO27izEYtY",
           "url":"http://weixin.qq.com/download",  
           "miniprogram":{
             "appid":"xiaochengxuappid12345",
             "pagepath":"index?foo=bar"
           },          
           "data":{
                   "first": {
                       "value":"恭喜你购买成功!",
                       "color":"#173177"
                   },
                   "keyword1":{
                       "value":"巧克力",
                       "color":"#173177"
                   },
                   "keyword2": {
                       "value":"39.8元",
                       "color":"#173177"
                   },
                   "keyword3": {
                       "value":"2014年9月22日",
                       "color":"#173177"
                   },
                   "remark":{
                       "value":"欢迎再次购买!",
                       "color":"#173177"
                   }
           }
       }

参数说明


微信公众号开发之发送模板消息_第4张图片

注:url和miniprogram都是非必填字段,若都不传则模板无跳转;若都传,会优先跳转至小程序。开发者可根据实际需要选择其中一种跳转方式即可。当用户的微信客户端版本不支持跳小程序时,将会跳转至url。

返回码说明

在调用模板消息接口后,会返回JSON数据包。正常时的返回JSON数据包示例:

{
           "errcode":0,
           "errmsg":"ok",
           "msgid":200228332
       }

相信看完以上文档,基本上没有什么问题了。
以下是我的部分代码:
微信模板消息

package com.learn.wecath.bean;

import java.util.HashMap;

/**
 * 微信模板消息
 */
public class WechatTemplateMessage {

    private String touser; //接收者openid
    private String template_id; //模板ID
    private String url; //模板跳转链接
    private HashMap> data; //data数据
    /**
     * 参数
     * @param value
     * @param color 可不填
     * @return
     */
    public static HashMap item(String value, String color) {
        HashMap params = new HashMap();
        params.put("value", value);
        params.put("color", color);
        return params;
    }

    public String getTouser() {
        return touser;
    }

    public void setTouser(String touser) {
        this.touser = touser;
    }

    public String getTemplate_id() {
        return template_id;
    }

    public void setTemplate_id(String template_id) {
        this.template_id = template_id;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public HashMap> getData() {
        return data;
    }

    public void setData(HashMap> data) {
        this.data = data;
    }
}
    /**
     * @param userList    接收消息的集合
     * @param gongdan 工单的信息 消息内容对象
     * @throws Exception
     */
    @Override
    public void pushGongdanToInstall(List userList, Gongdan gongdan) throws Exception {
        logger.info("推送信息给申请人;");
        //安装地点
        String content = "";
        Date now = new Date();
        //模板消息
        WechatTemplateMessage templateMessage = new WechatTemplateMessage();
        //参数
        HashMap> data = new HashMap<>(16);
        //根据具体模板参数组装
        String black = WechatTemplateColourEnum.BLACK.getDesc();
        String firstStr = "详细内容:你有一个新的订单需要处理,请及时确认。";
        data.put(WechatTemplateRowEnum.FIRST.getDesc(), WechatTemplateMessage.item(firstStr, black));
        data.put(WechatTemplateRowEnum.KEYWORD1.getDesc(), WechatTemplateMessage.item(gongdan.getOrderNum(), black));
        data.put(WechatTemplateRowEnum.KEYWORD2.getDesc(), WechatTemplateMessage.item(DateUtil.dateTime(now), black));
        data.put(WechatTemplateRowEnum.KEYWORD3.getDesc(), WechatTemplateMessage.item(content, black));
        String remarkStr = "感谢您的配合!";
        data.put(WechatTemplateRowEnum.REMARK.getDesc(), WechatTemplateMessage.item(remarkStr, black));

        //设置参数
        templateMessage.setData(data);
        //设置模板id
        templateMessage.setTemplate_id(PropertiesUtil.getProperty("subscriberTemplateId"));
        for (User user : userList){
            logger.info("推送用户id:" + user.getUserId());
            //设置推送用户
            templateMessage.setTouser(user.getOpenId());
            //推送消息
            WechatTemplateMessageUtil.sendTemplateMessage(templateMessage);
        }
        logger.info("推送信息给申请人结束:" + gongdan.getId());
    }

WechatTemplateMessageUtil 发送模板工具类

package com.learn.wecath.util;

import com.learn.wecath.bean.WechatTemplateMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 微信发送模板工具类
 */
public class WechatTemplateMessageUtil {

    private static final Logger logger = LoggerFactory.getLogger(WechatTemplateMessageUtil.class);

    //发送模板消息url
    public static final String TEMPLATE_SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";

    /**
     * @Author: feijq
     * @Description:模板发送工具类
     * @Date: 2019/11/26 14:56
     **/
    public static String sendTemplateMessage(WechatTemplateMessage templateMessage) throws Exception{
        String data = JsonUtil.toJson(templateMessage);
        String url = TEMPLATE_SEND_URL.replace("ACCESS_TOKEN", WechatAccessTokenUtil.getAccessToken());
        logger.info("发送模板消息,发送数据:" + data);
        String rtn = HttpClient.httpsRequest(url, "POST", data);
        logger.info("发送模板消息返回参数:" + rtn);
        return rtn;
    }
}

微信请求令牌工具栏

package com.learn.wecath.util;

import com.alibaba.fastjson.JSONObject;
import com.learn.wecath.config.RedisHelper;
import com.learn.wecath.config.WechatHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 微信请求令牌工具栏
 */
public class WechatAccessTokenUtil {

    private static final Logger logger = LoggerFactory.getLogger(WechatAccessTokenUtil.class);

    private static final String TOKENURL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+
            WechatHelper.getWechatHelper().getAppId()+"&secret="+ WechatHelper.getWechatHelper().getAppSecret();

    //access_token在redis中的key
    private static final String WECHAT_ACCESS_TOKEN_REDIS_KEY = "wechat_access_token_redis_key";

    //access_token有效时间1.5小时,微信为2小时
    private static final int WECHAT_ACCESS_TOKEN_EXPIRE_SECONDS = 5400;

    /**
     * 获取access_token,先从redis中查,查到返回,
     * 未查到去微信获取存到redis中,有效期1.5小时
     * @return
     */
    public static String getAccessToken(){
        String token = RedisHelper.getRedisHelper().getEntity(WECHAT_ACCESS_TOKEN_REDIS_KEY);
        if(!StringUtil.isEmpty(token)){
            return token;
        }
        String response = HttpClient.httpClientGet(TOKENURL);
        logger.info("获取accesstoken,url = " + TOKENURL);
        logger.info("获取accesstoken response==" + response);
        JSONObject rtnJson = JSONObject.parseObject(response);
        token = rtnJson.getString("access_token");
        RedisHelper.getRedisHelper().setExEntity(WECHAT_ACCESS_TOKEN_REDIS_KEY,WECHAT_ACCESS_TOKEN_EXPIRE_SECONDS,token);
        return token;
    }
}

RedisHelper 工具

package com.learn.wecath.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;

/**
 * @author lzj on 2017/2/21.
 */
public class RedisHelper {

    private static final Logger logger = LoggerFactory.getLogger(RedisHelper.class);

    private static ExtRedisPool redisHelper = null;
    private static ExtRedisPool tokenRedisHelper = null;
    /**
     * 失效监听数据库
     */
    private static ExtRedisPool expireListenerRedisHelper = null;

    public static void init(String path) {
        try {
            redisHelper = new ExtRedisPool(path);
            int tokenDbIndex = Integer.parseInt(redisHelper.getInitProperties().getProperty("redis.tokenDbIndex", "0"));
            int expireListenerDbIndex = Integer.parseInt(redisHelper.getInitProperties().getProperty("redis.expireListenerDbIndex", "0"));

            if (tokenDbIndex > 0) {
                tokenRedisHelper = new ExtRedisPool(path);
                tokenRedisHelper.setDbIndex(tokenDbIndex);
            }
            if (expireListenerDbIndex > 0) {
                expireListenerRedisHelper = new ExtRedisPool(path);
                expireListenerRedisHelper.setDbIndex(expireListenerDbIndex);
            }
            logger.info("RedisHelper redis pool 初始化OK");
        } catch (Exception ex) {
            logger.error("RedisHelper redis pool 初始化 error  ", ex);
        }
    }

    public static void init(InputStream path) {
        try {
            path.mark(0);
            redisHelper = new ExtRedisPool(path);
            int tokenDbIndex = Integer.parseInt(redisHelper.getInitProperties().getProperty("redis.tokenDbIndex", "0"));
            int expireListenerDbIndex = Integer.parseInt(redisHelper.getInitProperties().getProperty("redis.expireListenerDbIndex", "0"));
            if (tokenDbIndex > 0) {
                tokenRedisHelper = new ExtRedisPool(path);
                tokenRedisHelper.setDbIndex(tokenDbIndex);
            }

            if (expireListenerDbIndex > 0) {
                path.reset();
                expireListenerRedisHelper = new ExtRedisPool(path);
                expireListenerRedisHelper.setDbIndex(expireListenerDbIndex);
            }
            logger.info("RedisHelper redis pool 初始化OK");
        } catch (Exception ex) {
            logger.error("RedisHelper redis pool 初始化 error  ", ex);
        }
    }


    /**
     * 根据用户设备iid返回 数据库
     *
     * @return DAOOperator
     */
    public static ExtRedisPool getRedisHelper() {
        return redisHelper;
    }

    public static ExtRedisPool getTokenRedisHelper() {
        return tokenRedisHelper;
    }

    public static ExtRedisPool getExpireListenerRedisHelper() {
        return expireListenerRedisHelper;
    }

    public static void registeRedisErrorHandler(RedisErrorHandler redisErrorHandler) {
        if (null != redisHelper) {
            redisHelper.setRedisErrorHandler(redisErrorHandler);
        }
    }
}

http请求工具类:


package car.repair.common.util;
 
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
 
import java.io.IOException;
 
/**
 * HttpClient工具类
 */
@Slf4j
public class HttpClientUtils {
/**
     * 发起https请求并获取结果
     *
     * @param requestUrl    请求地址
     * @param requestMethod 请求方式(GET、POST)
     * @param outputStr     提交的数据
     * @return String
     */
    public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
        StringBuffer buffer = new StringBuffer();
        String result = "";
        try {
            // 创建SSLContext对象,并使用我们指定的信任管理器初始化
            TrustManager[] tm = {new CxX509TrustManager()};
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new 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();
            result = buffer.toString();
        } catch (ConnectException ce) {
            logger.error("Weixin server connection timed out.", ce);
        } catch (Exception e) {
            logger.error("Whttps request error:{}", e);
        }
        return result;
    } 

    /**
     * 以jsonString形式发送HttpPost的Json请求,String形式返回响应结果
     *
     * @param url
     * @param jsonString
     * @return
     */
    public static String sendPostJsonStr(String url, String jsonString) throws IOException {
        if (jsonString == null || jsonString.isEmpty()) {
            return sendPost(url);
        }
        String resp = "";
        StringEntity entityStr = new StringEntity(jsonString,
                ContentType.create("text/plain", "UTF-8"));
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        httpPost.setEntity(entityStr);
        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            resp = EntityUtils.toString(entity, "UTF-8");
            EntityUtils.consume(entity);
        } catch (ClientProtocolException e) {
            log.error(e.getMessage());
        } catch (IOException e) {
            log.error(e.getMessage());
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    log.error(e.getMessage());
                }
            }
        }
        if (resp == null || resp.equals("")) {
            return "";
        }
        return resp;
    }
 
    /**
     * 发送不带参数的HttpPost请求
     *
     * @param url
     * @return
     */
    public static String sendPost(String url) throws IOException {
        // 1.获得一个httpclient对象
        CloseableHttpClient httpclient = HttpClients.createDefault();
        // 2.生成一个post请求
        HttpPost httppost = new HttpPost(url);
        CloseableHttpResponse response = null;
        try {
            // 3.执行get请求并返回结果
            response = httpclient.execute(httppost);
        } catch (IOException e) {
            log.error(e.getMessage());
        }
        // 4.处理结果,这里将结果返回为字符串
        HttpEntity entity = response.getEntity();
        String result = null;
        try {
            result = EntityUtils.toString(entity);
        } catch (ParseException | IOException e) {
            log.error(e.getMessage());
        }
        return result;
    }
}

收到消息,我就不自己弄图了。这里附上官方图片一张:

你可能感兴趣的:(微信公众号开发之发送模板消息)