之前写的小程序项目有一个向用户推送消息的功能,一开始打算使用小程序提供的模板消息但是后来发现小程序发送模板消息有很大的局限性,小程序发送模板消息需要收集用户提交表单生成的formId,而这个formId只能使用一次,且有效时间为七天,也就是说你不能主动通过微信向用户发送消息,只有当用户主动触发表单事件,你拿到生成的fomId才能调用API发送消息,所以用起来很不方便。所以改用小程序绑定公众号,通过公众号来发送模板消息,不过需要用到公众号与用户对应的openid,这个openid和你在小程序里获得的openid不一样,小程序得到的openid是用户与你的小程序对应的唯一id,所以调用公众号发送模板消息接口自然要使用用户对应公众号的openid。那么怎么在小程序里获得用户对应公众号的openid呢?这里需要在小程序里用web-view组件打开公众号授权网页授权有两种方式:静默授权和手动授权。区别请查看网页授权文档授权后会携带参数到你设置的redirect_uri页面,我直接把redirect_uri填写成我的后台接口接收code,你也可以写个页面来接收,不过需要在小程序里配置业务域名我的大致流程就是用户在小程序里完成登录后会直接打开公众号授权页面,因为是静默授权,所以用户只能看到空白页面,此后我后台的接口就可以接收到授权成功传给我的参数,但是在小程序里就无法跳回主界面了,我们使用了页面加载定时器,在授权页面打开后三秒跳回小程序主界面`Page({
data:{url:‘’},
onLoad:function(){console.log(‘我返回了’)setTimeout(function(){wx.reLaunch({url:‘…/info/info’,})},3000)},
})`这里需要在公众号配置授权回调页面域名,你的redirect_uri必须在此域名下重点来了,你必须在创建账号并将你的小程序和服务号绑定在其下,这样你就可以获取unionid,unionid对应开放平台下的小程序和公众号是唯一的,也就是说一个微信用户在你的小程序中的onionid和在你公众号下的onionid是相同的,这样我们就可以在用户登录小程序时获得用户的openid和unionid,在完成授权后又可以调用接口获得openid2和unionid,通过unionid我们就可以将小程序用户和公众号用户关联起来,换句话说就是你可以通过查询unionid知道完成网页授权的用户是你的哪个小程序用户了,在之后的发送模板消息功能就可以获得你小程序用户的openid2(用户对应公众号的openid)来调接口了
获得小程序openid和unionid:
@SuppressWarnings("unchecked")//获取小程序用户的openid,unionidprivateMapString,StringgetSessionByCode(Stringcode){//code是从小程序调用wx.login拿到的codeStringurl="https://api.weixin.qq.com/sns/jscode2session?appid="+appId1+"&secret="+appSecret1+"&js_code="+code+"&grant_type=client_credential";//发送请求Stringdata=HttpUtil.get(url);ObjectMappermapper=newObjectMapper();MapString,Stringjson=null;try{json=mapper.readValue(data,Map.class);}catch(Exceptione){e.printStackTrace();}//形如{"session_key":"6w7Br3JsRQzBiGZwvlZAiA==","openid":"oQO565cXXXXXEvc4Q_YChUE8PqB60Y"}的字符串returnjson;}拿到openid和unionid就存入你的用户表中
获得公众号openid2和unionid:
@RequestMapping(value="/getOpenid2")//获得公众号openid,此接口为授权回调接口redirect_uripublic@ResponseBodyvoidgetOpenid(HttpServletRequestrequest)throwsException{Stringcode=request.getParameter("code");//公众号授权codeStringopenid2=getOpenidByCode(code).get("openid");//获得openid2MapString,Stringuserinfo=WxTemplate.getUserinfo(openid2,appId2,appSecret2);//获取用户详细信息Stringunionid=userinfo.get("unionid");//unionidloginService.addOpenid2ByUnionid(openid2,unionid);//根据unionid将openid2存入用户表中}HttpUtil:
publicclassHttpUtil{privatestaticfinalStringCharset="utf-8";/发送请求,如果失败,会返回null@paramurl@parammap@return/publicstaticStringpost(Stringurl,MapString,Stringmap){//处理请求地址try{HttpClientclient=HttpClientBuilder.create().build();URIuri=newURI(url);HttpPostpost=newHttpPost(uri);//添加参数ListNameValuePairparams=newArrayListNameValuePair();for(Stringstr:map.keySet()){params.add(newBasicNameValuePair(str,map.get(str)));}post.setEntity(newUrlEncodedFormEntity(params,Charset));//执行请求HttpResponseresponse=client.execute(post);if(response.getStatusLine().getStatusCode()==200){//处理请求结果StringBufferbuffer=newStringBuffer();InputStreamin=null;try{in=response.getEntity().getContent();BufferedReaderreader=newBufferedReader(newInputStreamReader(in,Charset));Stringline=null;while((line=reader.readLine())!=null){buffer.append(line);}}catch(Exceptione){e.printStackTrace();}finally{//关闭流if(in!=null)try{in.close();}catch(Exceptione){e.printStackTrace();}}returnbuffer.toString();}else{returnnull;}}catch(Exceptione1){e1.printStackTrace();}returnnull;}/发送请求,如果失败会返回null@paramurl@paramstr@return/publicstaticStringpost(Stringurl,Stringstr){//处理请求地址try{HttpClientclient=HttpClientBuilder.create().build();URIuri=newURI(url);HttpPostpost=newHttpPost(uri);post.setEntity(newStringEntity(str,Charset));//执行请求HttpResponseresponse=client.execute(post);if(response.getStatusLine().getStatusCode()==200){//处理请求结果StringBufferbuffer=newStringBuffer();InputStreamin=null;try{in=response.getEntity().getContent();BufferedReaderreader=newBufferedReader(newInputStreamReader(in,"utf-8"));Stringline=null;while((line=reader.readLine())!=null){buffer.append(line);}}finally{//关闭流if(in!=null)in.close();}returnbuffer.toString();}else{returnnull;}}catch(Exceptione){e.printStackTrace();}returnnull;}/发送GET方式的请求,并返回结果字符串。br时间:2017年2月27日,作者:http://wallimn.iteye.com@paramurl@return如果失败,返回为null/publicstaticStringget(Stringurl){try{HttpClientclient=HttpClientBuilder.create().build();URIuri=newURI(url);HttpGetget=newHttpGet(uri);HttpResponseresponse=client.execute(get);if(response.getStatusLine().getStatusCode()==200){StringBufferbuffer=newStringBuffer();InputStreamin=null;try{in=response.getEntity().getContent();BufferedReaderreader=newBufferedReader(newInputStreamReader(in,Charset));Stringline=null;while((line=reader.readLine())!=null){buffer.append(line);}}finally{if(in!=null)in.close();}returnbuffer.toString();}else{returnnull;}}catch(Exceptione){e.printStackTrace();}returnnull;}}WxTemplate:
publicclassWxTemplate{@SuppressWarnings("unchecked")publicstaticMapString,StringgetUserinfo(Stringopenid2,StringappId2,StringappSecret2){//获得用户关于公众号的详细信息Stringaccess_token=getAccess_token(appId2,appSecret2);StringuserInfo=HttpUtil.get("https://api.weixin.qq.com/cgi-bin/user/info?access_token="+access_token+"&openid="+openid2+"&lang=zh_CN");ObjectMappermapper2=newObjectMapper();MapString,Stringjson2=null;try{json2=mapper2.readValue(userInfo,Map.class);}catch(Exceptione){e.printStackTrace();}returnjson2;}@SuppressWarnings("unchecked")publicstaticvoidsendMsg(Stringopenid2,Stringid,Stringtype,StringcheckTime,StringappId2,StringappSecret2){//发送模板消息WxMssVowx=newWxMssVo();//发送模板消息请求参数封装对象wx.setTouser(openid2);wx.setTemplate_id("1FePKYxjLfISyDLvuzDXjOmIk3QmG3EMbusfNQD76Lk");MapString,Stringminiprogram=newHashMap();miniprogram.put("appid","你的小程序appid");miniprogram.put("pagepath","pages/checked/checked?id="+id);wx.setMiniprogram(miniprogram);MapString,Stringfirst=newHashMap();MapString,Stringkeyword1=newHashMap();MapString,Stringkeyword2=newHashMap();MapString,Stringremark=newHashMap();first.put("value","您的"+type+"申请已通过审核");first.put("color","#173177");keyword1.put("value","申请通过");keyword1.put("color","#173177");keyword2.put("value",checkTime);keyword2.put("color","#173177");remark.put("value","点击查看详情");remark.put("color","#173177");MapString,MapString,Stringmap=newHashMap();map.put("first",first);map.put("keyword1",keyword1);map.put("keyword2",keyword2);map.put("remark",remark);wx.setData(map);StringjsonString=JSON.toJSONString(wx);Stringaccess_token=getAccess_token(appId2,appSecret2);Stringdata=HttpUtil.post("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="+access_token,jsonString);System.out.println(data);}@SuppressWarnings("unchecked")privatestaticStringgetAccess_token(StringappId2,StringappSecret2){//获得公众号access_tokenStringaccess_token=CacheManager.get("access_token");//从缓存中获取access_tokenif(access_token==null){access_token=HttpUtil.get("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appId2+"&secret="+appSecret2);ObjectMappermapper=newObjectMapper();MapString,Stringjson;try{json=mapper.readValue(access_token,Map.class);access_token=json.get("access_token");CacheManager.set("access_token",access_token,72001000);//将access_token存入缓存,设置过期时间为两个小时}catch(Exceptione){e.printStackTrace();}}returnaccess_token;}}发送模板消息请求参数封装对象:
publicclassWxMssVo{privateStringtouser;//openid2privateStringtemplate_id;//模板idprivateMapString,Stringminiprogram;//小程序appidprivateMapString,MapString,Stringdata;//数据publicMapString,StringgetMiniprogram(){returnminiprogram;}publicvoidsetMiniprogram(MapString,Stringminiprogram){this.miniprogram=miniprogram;}publicStringgetTouser(){returntouser;}publicvoidsetTouser(Stringtouser){this.touser=touser;}publicStringgetTemplate_id(){returntemplate_id;}publicvoidsetTemplate_id(Stringtemplate_id){this.template_id=template_id;}publicMapString,MapString,StringgetData(){returndata;}publicvoidsetData(MapString,MapString,Stringdata){this.data=data;}}缓存管理类:
publicclassCacheManager{@SuppressWarnings("rawtypes")privatestaticMapString,CacheDatacache=newConcurrentHashMap();/启动定时任务清理过期缓存,避免内存溢出/static{Timert=newTimer();t.schedule(newClearTimerTask(cache),0,70001000);}/设置缓存,不过期@paramkey@paramt/publicstaticTvoidset(Stringkey,Tt){cache.put(key,newCacheData(t,0));}/设置缓存,指定过期时间expire(单位毫秒)@paramkey@paramt@paramexpire过期时间/publicstaticTvoidset(Stringkey,Tt,longexpire){cache.put(key,newCacheData(t,expire));}/根据key获取指定缓存@paramkey@return/@SuppressWarnings("unchecked")publicstaticTTget(Stringkey){CacheDataTdata=cache.get(key);if(null==data){returnnull;}if(data.isExpire()){remove(key);returnnull;}returndata.getData();}/移除指定key缓存@paramkey/publicstaticvoidremove(Stringkey){cache.remove(key);}/移除所有缓存/publicstaticvoidremoveAll(){cache.clear();}privatestaticclassCacheDataT{//缓存数据privateTdata;//过期时间(单位,毫秒)privatelongexpireTime;publicCacheData(Tt,longexpire){this.data=t;if(expire=0){this.expireTime=0L;}else{this.expireTime=Calendar.getInstance().getTimeInMillis()+expire;}}/判断缓存数据是否过期@returntrue表示过期,false表示未过期/publicbooleanisExpire(){if(expireTime=0){returnfalse;}if(expireTimeCalendar.getInstance().getTimeInMillis()){returnfalse;}returntrue;}publicTgetData(){returndata;}}/清理过期数据定时任务/privatestaticclassClearTimerTaskextendsTimerTask{@SuppressWarnings("rawtypes")MapString,CacheDatacache;@SuppressWarnings("rawtypes")publicClearTimerTask(MapString,CacheDatacache){this.cache=cache;}@Overridepublicvoidrun(){SetStringkeys=cache.keySet();for(Stringkey:keys){CacheData?data=cache.get(key);if(data.expireTime=0){continue;}if(data.expireTimeCalendar.getInstance().getTimeInMillis()){continue;}cache.remove(key);System.out.println("remove"+key);}}}}模板id需要去模板库中挑选或者自己申请新的模板,不过审核时间有点长
代码有不足之处请各位大佬指出
最新资讯
-

小程序制作平台选型踩坑记录:2026年五大主流方案横向对比
2026 年微信小程序月活达 10.7 亿、覆盖 108 个行业,本次横向对比即速应用、乔拓云、凡科、有赞、微盟五大主流平台,分三阶段给出选型结论,核心聚焦成本、扩展性、运营能力三大维度。 -

即速应用,赋能企业玩转微信小程序智慧经营
作为国内领军的智慧商业经营服务商,即速应用始终秉承“让每个企业都拥有自己的智慧店铺”的愿景,持续赋能更多企业玩转智慧经营。即速应用旗下拥有“小程序搭建工具-即速应用”、“私域流量专家-即客云”等产品,帮助商家打通互联网全生态营销闭环。 -

即客云2.0重磅更新,让微信小程序运营更简单!
即客云作为一款基于企业微信的第三方工具,现从多维度提供超过30种功能,自上线以来,已服务多家企业,受到一致好评。近期,我们根据客户反馈和市场调研正式推出升级版 即客云2.0!更新了私域运营SOP,群日历功能,批量拓客,客户雷达,消息推送,个人欢迎语,帮助企业更好运用企业微信;同时提升了社群运营工作标准化,提升运营效率,帮助企业实现客户增长,玩转私域流量。










