赞
踩
最近看了一个地推的公众号,每天都会给你推送好几条地推需要的模板消息,好一段时间没有做公众号开发了,最近刚申请了个服务号,刚好可以拿来开发。模板消息需要服务号才可以,申请服务号的话需要企业营业执照,个人的话是没有办法申请的。下面来分享一下我的开发过程。
找不到的话,就在新功能上面去添加;
#公众号配置
wechat:
appid: APPID
appkey: APP密钥
messageId: 模板ID
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
@Data
public class WechatConfig {
@Value("${wechat.appid}")
private String appid;
@Value("${wechat.appkey}")
private String appkey;
}
这里有点类似登录吧,就是用咱们的APPID跟APP密钥送到官方接口那边去验证身份,如果没问题人家就给你返回一个token,方便后面调用接口可以传,让官方接口知道是谁发过来的。token是临时的,有效期是2个小时.
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
@Component public class ConfigurationService { private String accessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&"; @Autowired private WechatConfig wechatConfig; public JSONObject getAccessToken() { String requestUrl = accessTokenUrl + "appid=" + wechatConfig.getAppid() + "&secret=" + wechatConfig.getAppkey(); String resp = HttpUtil.get(requestUrl); JSONObject result = JSONUtil.parseObj(resp); System.out.println("获取access_token:" + resp); return result; } }
因为我们在发送模板消息的时候,需要填推送的对象(openid),
所以我们需要先查询出用户,再一个个推送。
/**
* 获取用户列表
* @param accessToken
* @return
*/
public JSONObject getUserList(String accessToken) {
String requestUrl = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=" + accessToken + "&next_openid=";
String resp = HttpUtil.get(requestUrl);
JSONObject result = JSONUtil.parseObj(resp);
System.out.println("用户列表:" + resp);
return result;
}
next_openid=这个可以为空,代表从头查起。也可以放上某个用户的openid,发送请求的到时候,用来告诉官方接口从哪个用户开始查起。因为查询一次,最多只能查一万条数据,假设你有几万个用户,那么你就需要查询好几次了,就需要用到这个参数。
因为我是将把配置写到数据库里面了,方便后面添加发送任务。大家不一定要做这部操作哈。!
@Data @TableName("template_msg") public class TemplateMsgEntity implements Serializable { private static final long serialVersionUID = 1L; /** * */ @TableId private Integer id; /** * 标题 */ private String tTitle; /** * 第一行 */ private String tKeyword1; /** * 第二行 */ private String tKeyword2; /** * 第三行 */ private String tKeyword3; /** * 第四行 */ private String tKeyword4; /** * 备注 */ private String tRemark; /** * 跳转连接 */ private String tUrl; /** * 模板编码 */ private String tCode; /** * 状态 */ private int tStatus; }
模板发送
public JSONObject sendMsg(TemplateMsgEntity messageVo, String token, String openId) { String requestUrl = " https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + token; Map<String,Object> content=new HashMap<>(); JSONObject data = JSONUtil.createObj(); data.put("first",new JSONObject().put("value",messageVo.getTTitle())); data.put("keyword1",new JSONObject().put("value",messageVo.getTKeyword1())); data.put("keyword2",new JSONObject().put("value",messageVo.getTKeyword2())); data.put("keyword3",new JSONObject().put("value",messageVo.getTKeyword3())); data.put("keyword4",new JSONObject().put("value",messageVo.getTKeyword4())); data.put("remark",new JSONObject().put("value",messageVo.getTRemark())); content.put("touser",openId); content.put("url",messageVo.getTUrl()); content.put("template_id","jbgHt8W8RNpRN2KZwvAMty40iiZU2sa9dqnFXOsCvqw"); content.put("data",data); String resp = HttpUtil.post(requestUrl,JSONUtil.parseFromMap(content).toString()); System.out.println(content.toString()); System.out.println(JSONUtil.parseFromMap(content)); JSONObject result = JSONUtil.parseObj(resp); System.out.println("发送消息:" + resp); return result; }
接口字段要对应着来。
官方文档:https://mp.weixin.qq.com/advanced/tmplmsg?action=faq&token=1066457355&lang=zh_CN
有个需要注意的地方就是,模板封装好之后,推送到官方提供的接口时,数据类型是String类型哦,别整个对象就过来,那样解析不了的。
/** * 发送模板消息 * @return */ @GetMapping( "/sedMsg") public JSONObject sedMsg(){ JSONObject accessToken = configurationService.getAccessToken(); String token=accessToken.getStr("access_token"); //获取用户列表 JSONObject userList = configurationService.getUserList(token); JSONArray openids = userList.getJSONObject("data").getJSONArray("openid"); System.out.println(openids.toArray()); TemplateMsgEntity messageVo=new TemplateMsgEntity(); messageVo.setTTitle("标题"); messageVo.setTKeyword1("测试1"); messageVo.setTKeyword2("测试2"); messageVo.setTKeyword3("测试3"); messageVo.setTKeyword4("测试4"); messageVo.setTRemark("remark"); for (Object openid:openids) { JSONObject resp = configurationService.sendMsg(messageVo,token,openid.toString()); } return null; }
由于ACCESS_TOKEN只有两个小时就过期,所以我们应该专门写一个服务,或者一个定时间任务,隔一段时间就去读取数据库中记录的access_token,并且将写入access_token的时间跟现在的时间进行比较,大概超过117分钟时,就重新刷新写到数据中去。思路是这样的,大家可以自己写哈,方式很多。
@Configuration @EnableScheduling public class MessageTask { @Autowired SysConfigService sysConfigService; @Autowired ConfigurationService configurationService; @Autowired TemplateMsgService templateMsgService; /** * 维护Token */ @Scheduled(fixedRate = 120000) public void tokenTask(){ System.out.println("定时任务开启:"); //获取token String token = sysConfigService.getValue("ACCESS_TOKEN"); JSONObject json = JSONUtil.parseObj(token); String expires_date = json.getStr("expires_date"); //token创建的时间 DateTime parse = DateUtil.parse(expires_date); //跟现在的时间对比是否大于7000s long between = DateUtil.between(parse, new DateTime(), DateUnit.MINUTE); System.out.println("时间比较:"+between); //快过期了,重新刷新token if (between>115){ JSONObject accessToken = configurationService.getAccessToken(); if (accessToken.getStr("expires_in")!=null&&accessToken.getStr("expires_in").equals("7200")){ accessToken.put("expires_date",DateUtil.now().toString()); sysConfigService.updateValueByKey("ACCESS_TOKEN",accessToken.toString()); System.out.println("token更新了:"+accessToken.toString()); } } } }
希望能帮助到大家
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。