任务描述
原本的消息推送分为两个类型,文本消息和图文消息。现在要将其中一部分修改为图文消息。参考: 微信文档 CSDN博客
准备工作
首先应该去微信的官方客服购买消息模板,购买以后会获得template_id_short,即模板库中模板的编号,有“TM**”和“OPENTMTM**”等形式。并且会有对应的模板样式,如下:
{{first.DATA}}
订单号:{{keyword1.DATA}}
商品名称:{{keyword2.DATA}}
收件人姓名:{{keyword3.DATA}}
收件人电话:{{keyword4.DATA}}
收件人地址:{{keyword5.DATA}}
{{remark.DATA}}
您提交的发货订单已发货
订单号:5244030005646
商品名称:某商品
收件人姓名:陈璐
收件人电话:13522211111
收件人地址:广东省 广州市 天河区 科韵北路112号
如有疑问,请尽快联系我们。
注意事项
- 模板中的关键字,必须与模板保持一致,否则模板并不会识别。如:{{first.DATA}},最后保存JSON 的时候,名字应为{"first",first}. 2.申请模板之后,模板的存储数量有限,所以需要写方法,将已经获取的模板id(template_id)存放在缓存或者数据库中,下一次以同样的appid和template_id_short去获取template_id时,先判断是否已经在缓存或数据库中存在,若不存在,再去获取。 3.微信中可以存放的模板id数量有限,所以需要方法去判断之前是否申请过模板id,保证模板id不会重复被申请。 4.如果模板出现错误,应该删除更新。 5.如果出现错误,去官方文档中可以查询到错误原因。 /暂时想到的就这么多,如果还有其他,欢迎补充/
###1. 获取access_token的方法
@Component
public class WxCacheManager extends CacheManager<String,Object> {
@Autowired
private JedisManager manager;
@Override
public int getDbIndex() {
return IConstants.DB_INDEX_VARIABLE;
}
@Override
public JedisManager getJedisManager() {
return manager;
}
/**
* 获取指定公众号的access_token
* @param appid 公众号的appid
* @return
*/
public String getTokenFromCache(String appid){
String access_token = (String)this.getByKey("access_token_" + appid);
if(Commons.isNull(access_token)){
String appsecret = WeixinUtil.getAppsecret(appid);
AccessToken accessToken = WeixinUtil.getAccessToken(appid, appsecret);
access_token = accessToken.getToken();
if(!Commons.isNull(access_token)){
this.setKeyValue("access_token_" + appid,access_token,7000);
}
}
return access_token;
}
/**
* 获得指定公众号的jsApiTicket
* @param appid 公众号的appid
* @return
*/
public String getJsApiTicketFromCache(String appid){
String jsApiTicket = (String)this.getByKey("jsApiTicket_" + appid);
if(Commons.isNull(jsApiTicket)){
JsApiTicket jsTicket = WeixinUtil.getJsTicket(getTokenFromCache(appid));
jsApiTicket = jsTicket.getTicket();
if(!Commons.isNull(jsApiTicket)){
this.setKeyValue("jsApiTicket_" + appid,jsApiTicket,7000);
}
}
return jsApiTicket;
}
/**
* 从缓存中查询微信用户信息
* @param appid
* @param openid
* @return
*/
public UserInfo getUserInfoFromCache(String appid, String openid){
UserInfo userinfo = (UserInfo)super.getByKey("userinfo_" + appid + "_" + openid);
if(Commons.isNull(userinfo)){
userinfo = WeixinUtil.getUserInfoByOpenid(this.getTokenFromCache(appid),openid);
if(userinfo!=null){
super.setKeyValue("userinfo_" + appid + "_" + openid,userinfo,3600);
}
}
return userinfo;
}
/**
* 将微信用户信息添加到缓存
* @param userinfo
* @param appid
*/
public void setUserInfoCache(UserInfo userinfo, String appid){
if(!Commons.isNull(userinfo) && !Commons.isNull(userinfo.getOpenid()) && !Commons.isNull(appid)){
this.setKeyValue("userinfo_" + appid + "_" + userinfo.getOpenid(),userinfo,3600);
}
}
/**
* 从缓存中获取指定公众号信息
* @param appid
* @return
*/
public Wbapp getWbappFromCache(String appid){
return null;
/*return (Wbapp)this.getByKey("wbapp_" + appid);*/
}
/**
* 将公众号信息添加到缓存
* @param wbapp
*/
public void setWbappCache(Wbapp wbapp){
if(!Commons.isNull(wbapp)){
this.setKeyValue("wbapp_" + wbapp.getAppid(),wbapp,7000);
}
}
/**
* 从缓存中查询用户基本信息
* @param id
* @return
*/
public WbUser getWbUserFromCache(Long id){
return null;
//return (WbUser)super.getByKey(WbUser.class.getCanonicalName() + id);
}
/**
* 将用户基本信息添加到缓存
* @param wbuser
*/
public void setWbUserCache(WbUser wbuser){
if(!Commons.isNull(wbuser)){
this.setKeyValue(WbUser.class.getCanonicalName() + wbuser.getId(),wbuser,7000);
}
}
public Long getSyncTimesFromCache(String appid){
return (Long)this.getByKey("wzc_synctimes_" + appid);
}
public void setSyncTimesCache(String appid,Long time){
if(!Commons.isNull(appid) && !Commons.isNull(time)){
this.setKeyValue("wzc_synctimes_" + appid,time,24*60*60);
}
}
}
2. 模板消息类
public class WxTemplate {
private String template_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;
}
}
3.设置每条模板消息信息的类
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;
}
}
4.模板消息使用方法部分
//消息类型
@Service
public class MessageUtil {
/**
* 发送模板消息
* @param appid
* @param openid
* @param template_id 模板id
* @param data 模板消息内容
* @param url URL置空,则在发送后,点击模板消息会进入一个空白页面(ios),或无法点击
*/
public static void sendTemplateMessage(String appid, String openid, String template_id, Map<String,TemplateData> data, String url, String template_id_short){
WxCacheManager wxCacheManager = SpringContextHolder.getBean(WxCacheManager.class);
WxTemplate wxTemplate = new WxTemplate();
wxTemplate.setTouser(openid);
wxTemplate.setTemplate_id(template_id);
//微信端页面是否有跳转,通过判断跳转链接是否为空来决定,所以当url为空时,将链接设置为""
if (url==null){
wxTemplate.setUrl("");
}else {
wxTemplate.setUrl(url);
}
wxTemplate.setData(data);
String access_token = wxCacheManager.getTokenFromCache(appid);
String request_url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + access_token;
JSONObject returnObj = com.xiangshi.wzc.wx.util.MessageUtil.httpRequest(request_url, "POST", JSONObject.fromObject(wxTemplate).toString());
if(returnObj.containsKey("errcode") && "40037".equals(returnObj.getString("errcode"))) {
ActiveMQQueue dest = new ActiveMQQueue("Wzc_template_List");
long delayTime = TimingConstants.DELAY_TIME_TWO_SECOND;
Map<String,Object> map = new HashMap<String, Object>();
map.put("appid", appid);
map.put("openid", openid);
map.put("template_id", template_id);
map.put("data", data);
map.put("url", url);
map.put("template_id_short", template_id_short);
JSONObject jsonObject = JSONObject.fromObject(map);
SendMessage sendMessage = SpringContextHolder.getBean(SendMessage.class);
sendMessage.sendSingle(jsonObject.toString(), dest, delayTime);
}
}
/**
* 获取模板id
* @param appid
* @param template_id_short 模板库中模板的编号
* @return
*/
public static String applyTemplateID(String appid,String template_id_short){
WxCacheManager wxCacheManager = SpringContextHolder.getBean(WxCacheManager.class);
String access_token = wxCacheManager.getTokenFromCache(appid);
String request_url = "https://api.weixin.qq.com/cgi-bin/template/api_add_template?access_token=" + access_token;
Map<String,String> map = new HashMap<String,String>();
map.put("template_id_short",template_id_short);
JSONObject resultObj = com.xiangshi.wzc.wx.util.MessageUtil.httpRequest(request_url, "POST", JSONObject.fromObject(map).toString());
if (resultObj.containsValue("ok")){
return String.valueOf(resultObj.get("template_id"));
}else {
return null;
}
}
/**
* 获取模板列表
* @param appid
* @return
*/
public static JSONArray getTemplateList(String appid) {
WxCacheManager wxCacheManager = SpringContextHolder.getBean(WxCacheManager.class);
String access_token = wxCacheManager.getTokenFromCache(appid);
String request_url = "https://api.weixin.qq.com/cgi-bin/template/get_all_private_template?access_token=" + access_token;
JSONObject resultObj = com.xiangshi.wzc.wx.util.MessageUtil.httpRequest(request_url, "GET", null);
if(resultObj.containsKey("template_list")) {
return resultObj.getJSONArray("template_list");
} else {
return null;
}
}
/**
* 根据模板id删除模板
* @param appid
* @param template_id
*/
public static void deleteTemplateById(String appid, String template_id) {
WxCacheManager wxCacheManager = SpringContextHolder.getBean(WxCacheManager.class);
String access_token = wxCacheManager.getTokenFromCache(appid);
String request_url = "https://api.weixin.qq.com/cgi-bin/template/del_private_template?access_token=" + access_token;
Map<String, String> map = new HashMap<String, String>();
map.put("template_id", template_id);
com.xiangshi.wzc.wx.util.MessageUtil.httpRequest(request_url, "POST", JSONObject.fromObject(map).toString());
}
public static void main(String[] args){
}
}
5.获取模板id的时候,判断模板是否已经存在,更新模板id
@Service
public class MessageWxTemplateServiceImpl extends BaseServiceImpl<MessageWxTemplate> implements MessageWxTemplateService {
@Autowired
private MessageWxTemplateDao messageWxTemplateDao;
@Autowired
private WxCacheManager cacheManager;
private static final String CACHE_PREFIX = "WXTemplateID_";
private static final Integer TIME_ONE_DAY_SECOND = 24 * 60 * 60;
@Override
protected BaseDao<MessageWxTemplate> getBaseDao() {
return messageWxTemplateDao;
}
@Override
public String getApplyTemplateID(String appid, String template_id_short){
String templateid = (String) cacheManager.getByKey(CACHE_PREFIX+appid+"_"+template_id_short);
if(templateid==null){
MessageWxTemplate messageWxTemplate = new MessageWxTemplate();
messageWxTemplate.setTemplate_id_short(template_id_short);
messageWxTemplate.setAppid(appid);
messageWxTemplate = messageWxTemplateDao.selectOne(messageWxTemplate);
if(messageWxTemplate==null){
templateid = MessageUtil.applyTemplateID(appid,template_id_short);
messageWxTemplate = new MessageWxTemplate();
messageWxTemplate.setTemplate_id_short(template_id_short);
messageWxTemplate.setAppid(appid);
messageWxTemplate.setTemplate_id(templateid);
this.insert(messageWxTemplate);
return templateid;
} else {
setTemplateCache(messageWxTemplate);
return messageWxTemplate.getTemplate_id();
}
} else {
return templateid;
}
}
@Override
public String updateTemplateID(String appid, String template_id, String template_id_short) {
//1-1.获取模板编号在数据库中对应的信息
MessageWxTemplate query = new MessageWxTemplate();
query = new MessageWxTemplate();
query.setAppid(appid);
query.setTemplate_id_short(template_id_short);
MessageWxTemplate template = messageWxTemplateDao.selectOne(query);
if (!Commons.isNull(template)) {
//1-2.清除缓存中数据
delTemplateCache(appid, template_id_short);
//1-3.将此错误模板信息从数据库删除
messageWxTemplateDao.deleteById(template.getId());
}
//1-4.获取数据库中平台所有的模板信息
query = new MessageWxTemplate();
query.setAppid(appid);
List<MessageWxTemplate> templates = messageWxTemplateDao.selectList(query);
//2.获取微信中平台所有的模板信息
JSONArray templatesWX = MessageUtil.getTemplateList(appid);
//3.比对,将错误的模板删掉(删掉的是所有的错误模板)
boolean next = true;
if (!Commons.isNull(templates) && templates.size() > 0
&& !Commons.isNull(templatesWX) && templatesWX.size() > 0 ) {
for (int i = 0; i < templatesWX.size(); i++) {
JSONObject templateInfo = templatesWX.getJSONObject(i);
//表示此模板是否需要删除,默认需要删除
boolean b = true;
if (templateInfo.containsKey("template_id")) {
//3-1.循环比较微信中的模板是否也在数据库中
for (MessageWxTemplate mwt : templates) {
//3-1-1.此模板存在,不需要删除
if (templateInfo.getString("template_id").equals(mwt.getTemplate_id())) {
b = true;
break;
}
}
if (!b) {
//3-1-2.此模板存在,需要删除
MessageUtil.deleteTemplateById(appid, templateInfo.getString("template_id"));
}
}
}
} else if ((Commons.isNull(templates) || templates.size() == 0)
&& !Commons.isNull(templatesWX) && templatesWX.size() > 0 ) {
for (int i = 0; i < templatesWX.size(); i++) {
JSONObject templateInfo = templatesWX.getJSONObject(i);
if (templateInfo.containsKey("template_id")) {
MessageUtil.deleteTemplateById(appid, templateInfo.getString("template_id"));
}
}
}
//5.根据template_id_short获取新的template_id
String new_template_id = MessageUtil.applyTemplateID(appid, template_id_short);
if (Commons.isNull(new_template_id)) {
return null;
}
return new_template_id;
}
@Override
public void insert(MessageWxTemplate entity) {
if(entity==null||entity.getTemplate_id_short()==null||entity.getAppid()==null||entity.getTemplate_id()==null){
return;
}
super.insert(entity);
setTemplateCache(entity);
}
private void setTemplateCache(MessageWxTemplate entity){
cacheManager.setKeyValue(CACHE_PREFIX+entity.getAppid()+"_"+entity.getTemplate_id_short(),
entity.getTemplate_id(),
TIME_ONE_DAY_SECOND);
}
private void delTemplateCache(String appid, String template_id_short){
cacheManager.deleteByKey(CACHE_PREFIX+appid+"_"+template_id_short);
}
}
6.发送模板消息
//获取模板id
String template_id = messageWxTemplateService.getApplyTemplateID(appid,"OPENTM*********");
if (template_id!=null||template_id!="") {
messages.setMsgtype("模板通知");
//修改为模板消息
//{{first.DATA}}
TemplateData first = new TemplateData();
first.setValue("您提交的发货订单已发货");
first.setColor("#173177 ");
//订单内容:{{keyword1.DATA}}
TemplateData keyword1 = new TemplateData();
keyword1.setValue(order.getProname());
keyword1.setColor("#173177 ");
//物流服务:{{keyword2.DATA}}
TemplateData keyword2 = new TemplateData();
keyword2.setValue(deliverOrder.getExpress());
keyword2.setColor("#173177 ");
//快递单号:{{keyword3.DATA}}
TemplateData keyword3 = new TemplateData();
keyword3.setValue(deliverOrder.getExpressno());
keyword3.setColor("#173177 ");
//收货信息:{{keyword4.DATA}}
TemplateData keyword4 = new TemplateData();
StringBuffer receiveMessage = new StringBuffer();
receiveMessage.append(deliverOrder1.getConsignee());
receiveMessage.append(" ");
receiveMessage.append(deliverOrder1.getConsigneemobile());
receiveMessage.append(" ");
receiveMessage.append(deliverOrder1.getP_c_d());
receiveMessage.append(" ");
receiveMessage.append(deliverOrder1.getAddress());
keyword4.setValue(receiveMessage.toString());
keyword4.setColor("#173177 ");
//{{remark.DATA}}
TemplateData remark = new TemplateData();
remark.setValue("\n如有疑问,请尽快联系我们。");
remark.setColor("#173177 ");
Map<String, TemplateData> data = new HashMap<>();
data.put("first", first);
data.put("keyword1", keyword1);
data.put("keyword2", keyword2);
data.put("keyword3", keyword3);
data.put("keyword4", keyword4);
data.put("remark", remark);
MessageUtil.sendTemplateMessage(appid,
wbUser1.getOpenid(),
template_id,
data,
Commons.getClientServer() + "/wzc/order/" + order.getId() + "?state=" + appid,
"OPENTM************");
最后的话
本来写工作日志是不打算公开的,毕竟觉得自己看看就好了,但是之前有人跟我说,公开之后,让别人看到,有人指出不足,会更好,所以还是公开好了~"OPENTM************"然后这一部分是被我手动注释掉了。写东西完全按照自己的思维来,比较乱。就是这样。