欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

微信公众号消息模板发送

程序员文章站 2023-12-28 17:32:34
...

微信公众号消息模板群发功能

开通申请模板消息功能

1 >> 在微信公众平台的后台,依次进入“功能->添加功能插件->模板消息”,即可申请模板消息(模板消息的申请需账号已经开通微信支付权限)

2 >> 点击申请

3 >> 申请时,选择2个和自己相关的行业即可

4 >> 提交并且申请通过后,可以在模板库中看到模板消息列表,选择一个匹配自己的模板消息点击详情添加(微信提供的模板消息里面基本已经涵盖的很全了,如果没有找到合适自己的也可以自己申请创建一个新的模板消息,我这里用的是一个现成的模板消息)

5 >> 申请完后就可以在自己的模板消息查看你要用的模板消息的id

获取模板消息发送所需参数

  1. 获取access_token
  2. 获取模板消息 template_id
  3. 获取标签 tagid 通过tagid 获取标签下用户的 openid
  4. 根据 申请审核的消息模板 创建 data
	"data":{
           "first": {
                "value":"您好!课程测试消息!",
                "color":"#173177"
            },
            "keyword1":{
                "value":"课程001",
                "color":"#173177"
            },
            "keyword2": {
                "value":"张老师",
                "color":"#173177"
            },
            "remark":{
                "value":"望准时参加",
                "color":"#173177"
            }
    };

AccessToken pojo类

	package net.mingsoft.common.wx.pojo;

import java.util.Calendar;

public class AccessToken {    
    // 获取到的凭证    
    private String token;    
    // 凭证有效时间,单位:秒    
    private Calendar expiresIn;    
    
    public String getToken() {    
        return token;    
    }    
    
    public void setToken(String token) {    
        this.token = token;    
    }

	public Calendar getExpiresIn() {
		return expiresIn;
	}

	public void setExpiresIn(Calendar expiresIn) {
		this.expiresIn = expiresIn;
	}    
    
}

TemplateData pojo类

	package net.mingsoft.common.wx.pojo;
/**
 * 模板数据
 * @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;
    }
}

WxTagsEntity pojo类

package net.mingsoft.common.wx.pojo;
public class WxTagsEntity {   
      
    private String id;  //标签id  
    private String name;  //标签名称
    private String count;  //此标签下粉丝数
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getCount() {
		return count;
	}
	public void setCount(String count) {
		this.count = count;
	}
}  

WxTemplate pojo类

package net.mingsoft.common.wx.pojo;
import java.util.Map;
/**
 * 模板基类
 * @author CLiang
 *
 */
public class WxTemplate {
    private String template_id;//模板ID
    private Integer tagid;//模板ID
    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 Integer getTagid() {
		return tagid;
	}
	public void setTagid(Integer tagid) {
		this.tagid = tagid;
	}
	public Map<String, TemplateData> getData() {
		return data;
	}
	public void setData(Map<String, TemplateData> data) {
		this.data = data;
	}
}
 

WxTemplateEntity pojo类

package net.mingsoft.common.wx.pojo;
public class WxTemplateEntity {   
      
    private String template_id;  //模板ID  
    private String title;  //模板标题  
    private String primary_industry;  //模板所属行业的一级行业  
    private String deputy_industry;  //模板所属行业的二级行业  
    private String content;  //模板内容  
    private String example;  //模板示例  
	public String getTemplate_id() {
		return template_id;
	}
	public void setTemplate_id(String template_id) {
		this.template_id = template_id;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getPrimary_industry() {
		return primary_industry;
	}
	public void setPrimary_industry(String primary_industry) {
		this.primary_industry = primary_industry;
	}
	public String getDeputy_industry() {
		return deputy_industry;
	}
	public void setDeputy_industry(String deputy_industry) {
		this.deputy_industry = deputy_industry;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public String getExample() {
		return example;
	}
	public void setExample(String example) {
		this.example = example;
	}
  
}  

微信公众号消息模板工具类

package net.mingsoft.common.wx.wxUtils;    
import java.io.BufferedReader;    
import java.io.InputStream;    
import java.io.InputStreamReader;    
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;    
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.net.ssl.HttpsURLConnection;    
import javax.net.ssl.SSLContext;    
import javax.net.ssl.SSLSocketFactory;    
import javax.net.ssl.TrustManager;
import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;    
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.convert.WritingConverter;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import cn.hutool.json.JSONException;
import net.mingsoft.common.wx.pojo.AccessToken;
import net.mingsoft.common.wx.pojo.JsApiTicket;
import net.mingsoft.common.wx.pojo.TemplateData;
import net.mingsoft.common.wx.pojo.WxTemplate;    
    
/**  
 * 公众平台通用接口工具类  
 *  
 */    
@Component
public class WeixinUtil {    
    private static Logger log = LoggerFactory.getLogger(WeixinUtil.class);    
    @Value("${weixin.AppId}")
	private String APPID;
	@Value("${weixin.AppSecret}")
	private String AppSecret;
	@Value("${weixin.domain}")
	private String domain;
	@Autowired
	private RestTemplate rest;
	 //创建一个静态map缓存  
    private static Map<String,Object> weixinCache = new HashMap<String, Object>();
    /**  
     * 发起https请求并获取结果  
     *   
     * @param requestUrl 请求地址  
     * @param requestMethod 请求方式(GET、POST)  
     * @param outputStr 提交的数据  
     * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)  
     */    
    public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {    
        JSONObject jsonObject = null;    
        StringBuffer buffer = new StringBuffer();    
        try {    
            // 创建SSLContext对象,并使用我们指定的信任管理器初始化    
            TrustManager[] tm = { new MyX509TrustManager() };    
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");    
            sslContext.init(null, tm, new java.security.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();    
            jsonObject = JSONObject.parseObject(buffer.toString());    
        } catch (ConnectException ce) {    
            log.error("Weixin server connection timed out.");    
        } catch (Exception e) {    
            log.error("https request error:{}", e);    
        }    
        return jsonObject;    
    }    
    
    // 获取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 = (AccessToken) weixinCache.get("accessToken"); 
        
        String request_url = access_token_url.replace("APPID", appid).replace("APPSECRET", appsecret);      
        if(accessToken != null){  
            Calendar current = Calendar.getInstance();  
            Calendar ever = accessToken.getExpiresIn();
            if(ever.before(current)){  
                JSONObject jsonObject = WeixinUtil.httpRequest(request_url, "GET", null);  
                weixinCache.remove("accessToken");  
                accessToken = new AccessToken();    
                long etime1=System.currentTimeMillis()+(jsonObject.getInteger("expires_in")*1000);//延时函数,单位毫秒,这里是延时了5分钟
                Date expiresIn = new Date(etime1);  
                Calendar ever1 = Calendar.getInstance();
                ever1.setTime(expiresIn); 
                accessToken.setExpiresIn(ever1); 
                accessToken.setToken(jsonObject.getString("access_token"));    
                weixinCache.put("accessToken", accessToken); 
                log.info("accessToken is invalid : --------------------------------"+accessToken.getToken(),WeixinUtil.class);
            }  
            log.info("accessToken is available : --------------------------------"+accessToken.getToken(),WeixinUtil.class);
        }else{  
            //同上面的else里的code  
            JSONObject jsonObject = WeixinUtil.httpRequest(request_url, "GET", null);  
            if(jsonObject.containsKey("errcode")&&jsonObject.getInteger("errcode")!=0) {
            	log.info("获取access_token 失败:"+jsonObject.toJSONString(),WeixinUtil.class);
            	return null;
            }
            weixinCache.remove("accessToken");  
            accessToken = new AccessToken();    
            accessToken.setToken(jsonObject.getString("access_token"));    
            long etime1=System.currentTimeMillis()+(jsonObject.getInteger("expires_in")*1000);//延时函数,单位毫秒,这里是延时了5分钟
            Date expiresIn = new Date(etime1);  
            Calendar ever1 = Calendar.getInstance();
            ever1.setTime(expiresIn); 
            accessToken.setExpiresIn(ever1); 
            weixinCache.put("accessToken", accessToken); 
            log.info("accessToken is null : --------------------------------"+accessToken.getToken(),WeixinUtil.class);
        } 
        return accessToken;    
    }   
    
    
   
    public static JsApiTicket getJsApiTicket(String accessToken){  
            String ticket_str = null;  
                    JsApiTicket jsApiTicket = (JsApiTicket) weixinCache.get("ticket");  
            if(jsApiTicket != null){  
                Calendar ever = jsApiTicket.getExpiresIn();  
                Calendar current = Calendar.getInstance();  
                if(ever.before(current)){  
                	String request_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi".replace("ACCESS_TOKEN", accessToken);  
                    JSONObject jsonObject = WeixinUtil.httpRequest(request_url, "GET", null);  
                    ticket_str = jsonObject.getString("ticket");  
                    weixinCache.remove("ticket");  
                    jsApiTicket = new JsApiTicket();  
                    Calendar ever1 = Calendar.getInstance();  
                    long etime1=System.currentTimeMillis()+(jsonObject.getInteger("expires_in")*1000);//延时函数,单位毫秒,这里是延时了5分钟
                    Date date=new Date(etime1);
                    ever1.setTime(date);
                    jsApiTicket.setExpiresIn(ever1);  
                    jsApiTicket.setTicket(ticket_str);  
                    weixinCache.put("ticket", jsApiTicket); 
                }  
            }else{  
                //同上面的else里的code  
            	String request_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi".replace("ACCESS_TOKEN", accessToken);  
                JSONObject jsonObject = WeixinUtil.httpRequest(request_url, "GET", null);  
                ticket_str = jsonObject.getString("ticket");  
                weixinCache.remove("ticket");  
                jsApiTicket = new JsApiTicket();  
                Calendar ever1 = Calendar.getInstance();  
                long etime1=System.currentTimeMillis()+(jsonObject.getInteger("expires_in")*1000);//延时函数,单位毫秒,这里是延时了5分钟
                Date date=new Date(etime1);
                ever1.setTime(date);
                jsApiTicket.setExpiresIn(ever1);  
                jsApiTicket.setTicket(ticket_str);  
                weixinCache.put("ticket", jsApiTicket); 
            }  
              
            return jsApiTicket;  
        } 
    
    
    //微信分享签名算法;
    public static Map<String, Object> sign(String jsapi_ticket, String url) {  
        Map<String, Object> ret = new HashMap<String, Object>();  
        String nonce_str = create_nonce_str();  
        String timestamp = create_timestamp();  
        String string1;  
        String signature = "";  
  
        //注意这里参数名必须全部小写,且必须有序  
        string1 = "jsapi_ticket=" + jsapi_ticket +  
                  "&noncestr=" + nonce_str +  
                  "&timestamp=" + timestamp +  
                  "&url=" + url;  
        System.out.println(string1);  
  
        try  
        {  
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");  
            crypt.reset();  
            crypt.update(string1.getBytes("UTF-8")); //对string1 字符串进行SHA-1加密处理  
            signature = byteToHex(crypt.digest());  //对加密后字符串转成16进制  
        }  
        catch (NoSuchAlgorithmException e)  
        {  
            e.printStackTrace();  
        }  
        catch (UnsupportedEncodingException e)  
        {  
            e.printStackTrace();  
        }  
  
        ret.put("url", url);  
        ret.put("jsapi_ticket", jsapi_ticket);  
        ret.put("nonceStr", nonce_str);  
        ret.put("timestamp", timestamp);  
        ret.put("signature", signature);  
  
        return ret;  
    }  
  
    private static String byteToHex(final byte[] hash) {  
        Formatter formatter = new Formatter();  
        for (byte b : hash)  
        {  
            formatter.format("%02x", b);  
        }  
        String result = formatter.toString();  
        formatter.close();  
        return result;  
    }  
    //生成随机字符串  
    private static String create_nonce_str() {  
        return UUID.randomUUID().toString().replace("-", "");  
    }  
    //生成时间戳字符串  
    private static String create_timestamp() {  
        return Long.toString(System.currentTimeMillis() / 1000);  
    } 
    
    
    /**
     * 获取网页授权凭证
     * 
     * 
     * @param code
     * @return WeixinAouth2Token
     */
    public JSONObject getOauth2AccessToken(String code) {
    	JSONObject jsonObject = null;
    	try {
    		// 拼接请求地址
    		String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+APPID+"&secret="+AppSecret+"&code="+code+"&grant_type=authorization_code";
    		//String requestUrl = "https://api.weixin.qq.com/sns/jscode2session?appid="+APPID+"&secret="+APPSECRET+"&js_code="+code+"&grant_type=authorization_code";
    		String resStr = rest.getForObject(requestUrl, String.class);
    		jsonObject=JSON.parseObject(resStr,JSONObject.class);
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
        return jsonObject;
    }
    /**
     * 获取网页授权凭证
     * 
     * 
     * @param code
     * @return WeixinAouth2Token
     */
    public String getOauth2Code(HttpServletRequest request) {
    	try {
//    		String uri = urlEncodeUTF8("http://6gsw4p.natappfree.cc/weChat/loginByWX");
    		String uri = urlEncodeUTF8("http://"+domain+"/weChat/loginByWX");
    		// 拼接请求地址
    		String requestUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+APPID+"&redirect_uri="+uri+"&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";
    		return requestUrl;
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
        return null;
    }
    /**
     * URL编码(utf-8)
     * 
     * @param source
     * @return
     */
    public static String urlEncodeUTF8(String source) {
        String result = source;
        try {
            result = java.net.URLEncoder.encode(source, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }
    
    /**
     * 发送模板消息前获取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 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);
        // 调用接口创建菜单
        JSONObject jsonObject = WeixinUtil.httpRequest(url, "POST", jsonMenu);
        //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;
    }
}  

消息模板群发消息

	@ApiOperation(value = "消息模板群发消息")
  	@RequestMapping("/groupSending")
  	@ResponseBody
  	public Result groupSending(@RequestBody(required=false) WxTemplate wxTemplate,HttpServletRequest request,HttpServletResponse response,HttpSession session){
  		Integer tagid=wxTemplate.getTagid();
  		String templateId=wxTemplate.getTemplate_id();
  		Map<String, TemplateData> map = wxTemplate.getData();
  		TemplateData templateData = map.get("first");
  		System.out.println("value= "+templateData.getValue());
  		System.out.println("color= "+templateData.getColor());
  		if(tagid==null) {
  			return Result.build(false, "9999","tagid不能为空");
  		}
  		if(StringUtils.isBlank(templateId)) {
  			return Result.build(false, "9999","templateId不能为空");
  		}
  		try {
  			Thread thread=new Thread() {
  				@Override
  				public void run() {
  					// TODO Auto-generated method stub
  					AccessToken accessToken = WeixinUtil.getAccessToken(APPID,AppSecret);
  		  			String url="https://api.weixin.qq.com/cgi-bin/user/tag/get?access_token="+accessToken.getToken();
  		  			JSONObject postData = new JSONObject();   
  		  			postData.put("tagid", tagid);
  		  			JSONObject body = rest.postForEntity(url, postData, JSONObject.class).getBody();
  		  			System.out.println(body.getJSONObject("data").getString("openid"));
  		  			String[] list =body.getJSONObject("data").getObject("openid", String[].class);
  		  			url="https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="+accessToken.getToken();
  		  			postData.remove("tagid");
  		  			postData.put("data", map);
  		  			postData.put("template_id", templateId);
  		  			postData.put("url", "");
  		  			for(String openid:list) {
  		  				postData.put("touser", openid);
  		  				String result = rest.postForEntity(url, postData, String.class).getBody();
  		  				log.info("模板消息发送:openid is "+openid+" and result is "+result,WeChatAction.class);
  		  			}
  				}
  			};
  			thread.start();
  		} catch (Exception e) {
  			// TODO: handle exception
  			e.printStackTrace();
  			return Result.error();
  		}
		return Result.ok("您的消息已发送成功");
  	}

上一篇:

下一篇: