最近在开发小程序中遇到一个需求:小程序的用户关注指定公众号,则小程序里需要通知用户的提醒消息可以做在公众号中。
首先我先把实现的整套流程先述说一遍,免得码友们走了弯路。
(我写的这个流程是非常正确的。但是代码是不能直接用的只能进行参照。但帖上去的代码都是正确的。我是以自己的知识并且参照该链接实现出来的。如果看不懂我写的可以观看该链接比较容易理解。本人文笔不太好,非喜勿喷。)
准备工作
1.首先要创建一个微信开发平台,进行开发者资质认证(费用:300rmb)把小程序和公众号绑定在该微信开发平台下并且小程序和公众号要进行微信认证(300rmb+300rmb)。
注:这一步是一定要做的,为什么要做?我来为大家解说一下。像我们开发小程序或者公众号的都知道,每个用户在不同的程序或者公众号中都会有一个唯一标识openid和unionid他们的值随着不同的程序而改变。既然我们要把小程序和公众号关联起来让公众号锁定小程序中的用户并对他们进行消息推送。那么小程序和公众号他们的用户信息必定会有一个共同的值来确定用户的唯一。那就是用户的unionid。在微信开发平台下面绑定了小程序和公众号那么他们的unionid就会一致,通过unionid就可以实现小程序与用户端的用户共享了。
.2.用小程序的appid和appsecret获取小程序的access_token获取code来进行微信授权获取到微信信息(储存到数据库)。但是因为用户微信的appid和unionid属于保密的信息所以还要需要一个解压接口来得到。下面我会贴上代码。
3.用公众号的appid和appsecret获取公众号的access_token来获取已关注的用户openid,再根据用户的openid获取用户的所有信息包括unionid(存到数据库)
4.接下来就是通过小程序用户的unionid去找到对应的公众号的unionid获取公众号下的openid,通过公众号api的模板消息推送接口就可实现该功能了。
代码实现(因本人目前只专注于后端开发,以下都是后端代码。也是后端开发需要实现该功能所做的事情)
第一步:创建微信开发平台并绑定小程序和公众号(这一步操作特别简单就不详细说了)
第二步:通过前端页面穿入的code进行授权获取用户信息
/Createdbyzhoufon2018/6/14.通过微信code获得微信用户的openid/publicclassGetWxOpenidByWxCode{@OverridepublicvoidmainProcess(Contextcx)throwsException{Stringwx_appid="小程序的appid";Stringwx_secret="小程序的secret";Stringwx_code="前端传过来的code";//通过三个以上三个参数发送请求Stringurl="https://api.weixin.qq.com/sns/jscode2sessionappid="+wx_appid+"&secret="+app_secret+"&js_code="+wx_code+"&grant_type=authorization_code";//通过封装好的get请求获取到用户的sessionKey和用户在小程序的openid这样MapString,Objectresult=HttpUtils.doGetHttps(url);LinkedHashMapString,ObjectlinkedHashMap=newLinkedHashMap();linkedHashMap.put("session_key",result.get("session_key"));linkedHashMap.put("openid",result.get("openid"));}}/Createdbyzfon2018/12/11.通过解密获取微信小程序的unionidapi开放数据校验与解密/publicclassGetWxAppletInfoByDecode{publicvoidmainProcess(Contextcx)throwsException{Stringopenid="";Stringsession_key="";StringencryptedData="";Stringiv="";Stringreturn_str=decryptionUserInfo(encryptedData,session_key,iv);inti=return_str.indexOf("unionId");intl=return_str.indexOf("watermark");System.out.println(i+"-------"+l);System.out.println(return_str.substring(i,l));Stringunionid=return_str.substring(i+10,l-3);}/小程序解密用户数据@paramencryptedData@paramsessionKey@paramiv@return/publicstaticStringdecryptionUserInfo(StringencryptedData,StringsessionKey,Stringiv){Stringresult="";//被加密的数据byte[]dataByte=Base64.decode(encryptedData);//加密秘钥byte[]keyByte=Base64.decode(sessionKey);//偏移量byte[]ivByte=Base64.decode(iv);try{//如果密钥不足16位,那么就补足.这个if中的内容很重要intbase=16;if(keyByte.length%base!=0){intgroups=keyByte.length/base+(keyByte.length%base!=0?1:0);byte[]temp=newbyte[groupsbase];fill(temp,(byte)0);System.arraycopy(keyByte,0,temp,0,keyByte.length);keyByte=temp;}//初始化Security.addProvider(newBouncyCastleProvider());Ciphercipher=Cipher.getInstance("AES/CBC/PKCS7Padding","BC");SecretKeySpecspec=newSecretKeySpec(keyByte,"AES");AlgorithmParametersparameters=AlgorithmParameters.getInstance("AES");parameters.init(newIvParameterSpec(ivByte));cipher.init(Cipher.DECRYPT_MODE,spec,parameters);//初始化byte[]resultByte=cipher.doFinal(dataByte);if(null!=resultByte&&resultByte.length0){result=newString(resultByte,"UTF-8");}}catch(Exceptione){e.printStackTrace();}returnresult;}}第三步:获取公众号的用户信息
/获取已关注服务号的所有用户信息bug:这里只能取到一万个用户(解决办法:微信公众号官网文档)Createdbyzfon2018/12/13./publicclassGetUserInfoByGZH{privatestaticStringsend_url="https://api.weixin.qq.com/cgi-bin/user/get?access_token=";staticStringaccess_token="";publicstaticvoidmain(String[]str)throwsException{ListMapString,Objectlist=getUserInfoByOpenid(getUsersOpenid());Contextcx=newContext(null,null,null,null);GZHUsergzhUser=newGZHUser(cx);gzhUser.insertIntoUserInfo(list);}//获取关注该公众号的openidpublicstaticMapString,ObjectgetUsersOpenid()throwsException{//获取小程序的access_token并把它当做参数拼接到模板消息发送接口当中。(access_token一般都是通过get方式拼接传入微信接口)MapString,Objectaccess_token_map=WxAppletTemplateMessage2.GetWxAccessToken2();access_token=(String)access_token_map.get("access_token");Stringurl=send_url+access_token;//通过工具类把请求接口和参数进行请求并返回调用结果MapString,Objectresult=HttpUtils.doGetHttps(url);//{"errcode":0,"errmsg":"ok","msgid":68036453858394114}returnresult;}//同伙openid获取用户信息publicstaticListMapString,ObjectgetUserInfoByOpenid(MapString,Objectmap)throwsException{ListMapString,Objectlist=newArrayList();MapString,Objectmap2=(MapString,Object)map.get("data");ListStringlist2=(ListString)map2.get("openid");for(Strings:list2){Stringsend_url2="https://api.weixin.qq.com/cgi-bin/user/info?access_token="+access_token+"&openid="+s+"&lang=zh_CN";Stringssss="";//通过工具类把请求接口和参数进行请求并返回调用结果MapString,Objectresult=HttpUtils.doGetHttps(send_url2);//{"errcode":0,"errmsg":"ok","msgid":68036453858394114}Contextcx=newContext(null,null,null,null);GZHUsergzhUser=newGZHUser(cx);Booleanbool=gzhUser.userIsEmpty((String)result.get("unionid"));if(bool==true){list.add(result);}}returnlist;}}第四步:通过公众号api的模板消息推送接口就可实现该功能了。
//开始发送模板消息publicstaticMapString,ObjectsendAppletTemplateMessage(MapString,Objectrequest_param)throwsException{//获取小程序的access_token并把它当做参数拼接到模板消息发送接口当中。(access_token一般都是通过get方式拼接传入微信接口)MapString,Objectaccess_token_map=GetWxAccessToken2();Stringaccess_token=(String)access_token_map.get("access_token");Stringurl=send_url+access_token;//通过工具类把请求接口和参数进行请求并返回调用结果MapString,Objectresult=HttpUtils.doPostHttps(url,request_param);//{"errcode":0,"errmsg":"ok","msgid":68036453858394114}returnresult;}//用户报名活动成功将活动基本信息告知给用户publicstaticMapString,ObjectjoinActivitySuccessMessage(Stringopenid,intactivity_id)throwsException{Contextcx=newContext(null,null,null,null);ActivityDaoactivityDao=newActivityDao(cx);MapString,ObjectavtMap=activityDao.get(activity_id);//请求数据MapString,Objectrequest_data=newHashMap();//消息模板idStringtemplate_id=Constants.joinActivitySuccess_Template_id;//公众号模板消息所要跳转的urlStringurl="https://studentgt.xmcedu.cn";//用户的openidStringuser_openid=openid;Stringactivity_introduce=(String)avtMap.get("activity_introduce");//消息模板参数Timestampts=(Timestamp)avtMap.get("activity_begin_time");StringtsStr="";DateFormatsdf=newSimpleDateFormat("yyyy/MM/ddHH:mm:ss");try{tsStr=sdf.format(ts);}catch(Exceptione){e.printStackTrace();}Stringfirst="你好,你已报名成功";Stringkeyword1=(String)avtMap.get("activity_name");//活动主题Stringkeyword2=tsStr;//活动时间Stringkeyword3=activity_introduce.substring(0,10)+".......";//活动地点Stringremark="点击此消息,跳转链接观看详情。";request_data.put("touser",user_openid);request_data.put("template_id",template_id);request_data.put("url",url);//data参数MapString,Objectdata=newHashMap();templateParam(data,"first",first,"#173177");templateParam(data,"keyword1",keyword1,"#173177");templateParam(data,"keyword2",keyword2,"#173177");templateParam(data,"keyword3",keyword3,"#173177");templateParam(data,"remark",remark,"#173177");//miniprogram参数:需要点击通知跳转至小程序才需要该参数,该参数有时点击通知则优先跳转到小程序,该参数不存在是则默认跳转到mp_template_msg参数中的url中。MapString,Objectminiprogram=newHashMap();//这里的appid是需要跳转的小程序的appidminiprogram.put("appid",Constants.wx_appid);miniprogram.put("pagepath","pages/home/active/active");request_data.put("miniprogram",miniprogram);request_data.put("data",data);//返回结果信息MapString,Objectsend_return=sendAppletTemplateMessage(request_data);System.out.println("wxmessage"+send_return.toString());returnrequest_data;}//新作业通知publicstaticMapString,ObjectnewJobMessageInform(Stringopenid,intnotice_id)throwsException{Contextcx=newContext(null,null,null,null);NoticeManagerDaonoticeManagerDao=newNoticeManagerDao(cx);MapString,ObjectnoticeMap=noticeManagerDao.get(notice_id);//请求数据MapString,Objectrequest_data=newHashMap();//消息模板idStringtemplate_id=Constants.new_job_Template_id;//公众号模板消息所要跳转的urlStringurl="https://studentgt.xmcedu.cn";//用户的openidStringuser_openid=openid;Stringcontent=noticeMap.get("content")+"...........";UseruserDao=newUser(cx);MapString,ObjectcMap=userDao.get((int)noticeMap.get("promulgator_id"));Stringuser_duty=(String)cMap.get("user_duty");//消息模板参数Timestampts=(Timestamp)noticeMap.get("up_date");StringtsStr="";DateFormatsdf=newSimpleDateFormat("yyyy/MM/ddHH:mm:ss");try{tsStr=sdf.format(ts);}catch(Exceptione){e.printStackTrace();}Stringfirst="您好,您有新的作业指令下达";Stringkeyword1=(String)cMap.get("user_duty");//科目Stringkeyword2=tsStr;//日期Stringkeyword3=content.substring(0,10)+".......";//内容Stringremark="您点击此消息,跳转链接观看详情。";request_data.put("touser",user_openid);request_data.put("template_id",template_id);request_data.put("url",url);//data参数MapString,Objectdata=newHashMap();templateParam(data,"first",first,"#173177");templateParam(data,"keyword1",keyword1,"#173177");templateParam(data,"keyword2",keyword2,"#173177");templateParam(data,"keyword3",keyword3,"#173177");templateParam(data,"remark",remark,"#173177");//miniprogram参数:需要点击通知跳转至小程序才需要该参数,该参数有时点击通知则优先跳转到小程序,该参数不存在是则默认跳转到mp_template_msg参数中的url中。MapString,Objectminiprogram=newHashMap();//这里的appid是需要跳转的小程序的appidminiprogram.put("appid",Constants.wx_appid);miniprogram.put("pagepath","pages/home/homeWork/homeWork");request_data.put("miniprogram",miniprogram);request_data.put("data",data);//返回结果信息MapString,Objectsend_return=sendAppletTemplateMessage(request_data);System.out.println("wxmessage"+send_return.toString());returnrequest_data;}publicstaticMapString,ObjecttemplateParam(MapString,Objectparams,Stringname,Stringvalue,Stringcolor){MapString,Objectparam=newHashMap();param.put("value",value);param.put("color",color);params.put(name,param);returnparams;}/获取access_token@return@throwsException/publicstaticMapString,ObjectGetWxAccessToken2()throwsException{Stringaccess_token="";XmcCacheUtil2xmcCacheUtil=XmcCacheUtil2.getInstance();Objectaccess_token_obj=xmcCacheUtil.get("WxDataCache","access_token_obj");MapString,Objectobj=newHashMap();if(access_token_obj!=null){obj=(MapString,Object)access_token_obj;Longexpires_time=Long.valueOf(obj.get("expires_time").toString());Longnow_time=System.currentTimeMillis();if(expires_time-now_time300){access_token=obj.get("access_token").toString();}}//查询缓存if(access_token.equals("")){Stringurl="https://api.weixin.qq.com/cgi-bin/token";Stringgrant_type="client_credential";MapString,Stringmap=newHashMap();map.put("grant_type",grant_type);map.put("appid",Constants.wx_appid_gzh);map.put("secret",Constants.wx_secret_gzh);//MapString,Objectrs=HttpUtils.doGet(url,map,"utf-8");url=url+"?appid="+Constants.wx_appid_gzh+"&secret="+Constants.wx_secret_gzh+"&grant_type="+grant_type;MapString,Objectrs=HttpUtils.doGetHttps(url);access_token=rs.get("access_token").toString();Longexpires_time=System.currentTimeMillis()+Integer.valueOf(rs.get("expires_in").toString())1000;rs.put("expires_time",expires_time);access_token_obj=rs;xmcCacheUtil.put("WxDataCache","access_token_obj",access_token_obj);obj=rs;}returnobj;}













