900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 微信小程序消息从公众号推送

微信小程序消息从公众号推送

时间:2022-02-24 22:29:57

相关推荐

微信小程序消息从公众号推送

.06.05更新

新的一年认证续费只需要续费公众号。

小程序可以自动关联认证。

一定要记得!!!!!!!

--------------------------------------------以下是原文------------------------------------------

上个礼拜研究了一下使用小程序从公众号推送。

写一个攻略记录一下(代码都贴出来了,有一些从我代码中是从数据库中拿值的,大家酌情更改)。

准备工作如下:

一阶段

1、注册微信公众号。

2、注册微信小程序(可以从公众号中快速生成。

3、注册微信开放平台。

二阶段

1、认证公众号(注意首先要认证公众号,300认证费。

2、从公众号中关联认证小程序(否则单独认证又要收300的认证费用,比较费钱。

3、认证微信开放平台(300认证费。

三阶段

1、将微信公众号和微信小程序绑定到微信开放平台下。

2、配置ip白名单(获取对外ip地址网站:/

准备工作完毕。

讲一下公众号和小程序推送之间需要用到的id(们)。

微信在小程序和公众号之间绑了多个id.(具体的话还是自己查看微信官方API对各个id做出的解释比较好。下面我只是简单解释一下。

openid:在小程序,公众号中的身份证,每个用户在同一个小程序,公众号中的openid是绝对不同的,公众号和小程序绑定关联也不会相同。

unionid:在绑定微信开发平台之后,小程序和公众号共通的id(这个就是公众号推送的关键,所以一定要绑定开发平台。

formid:小程序推送用的id,有时长等条件限制,一般是你cue它一下,它改变值推送一下,无法长久有效推送。

推送原理。

公众号的推送是根据openid的推送的。

但公众号id获取被微信卡死了,规则为:必须要先获取openid,然后根据openid获取unionid.

当用户在小程序中操作的时候,可以根据小程序的openid找到小程序和公众号公共的unionid,然后再去找公众号的openid进行推送。

关系示例图如下:

推送步骤。

1、获取小程序用户openid和unionid.

2、获取公众号用户openid和unionid.

3、进行推送。

-----------------------------------------------虽然推送过程看起来很简单但其实中间有一点坑所以还是贴了代码-------------------------------

1、获取小程序openid和unionid。

【坑预警!!!!】

小程序的openid和unionid获取有两种方法。

①是直接从后台通过微信校验接口:

String url = "https://api./sns/jscode2session?appid="+APPID+ "&secret="+SECRET+"&js_code="+ wechatCode +"&grant_type=authorization_code";获取。好处是直接一次性就能获取openid,unionid和sessionkey.

然后这种获取方式用户必须关注了公众号后使用小程序才能拿到unionid。否则unionid为空

接口主要方法如下:

@ResponseBody@RequestMapping(value="/checkWechatUser.do")public LayUIResult checkWechatUser(HttpServletRequest request){LayUIResult result = new LayUIResult();try{String APPID = “自己的小程序appid”;String SECRET = "自己的小程序密码";String wechatCode = “自己的小程序wechatCode”;if(ObjectUtil.isNull(wechatCode)){result.setCode(1);result.setStatus(1);result.setMsg("微信凭证不能为空");return result;}//System.out.println("微信请求了服务");//请求腾讯微信校验接口String url = "https://api./sns/jscode2session?appid="+APPID+"&secret="+SECRET+"&js_code="+ wechatCode +"&grant_type=authorization_code";RestTemplate restTemplate = new RestTemplate();//进行网络请求,访问url接口ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, null, String.class);//根据返回值进行后续操作if(responseEntity != null && responseEntity.getStatusCode() == HttpStatus.OK){String sessionData = responseEntity.getBody();//System.out.println("调用了微信平台接口");Gson gson = new Gson();//解析从微信服务器获得的openid和session_key;WeChatSession weChatSession = gson.fromJson(sessionData,WeChatSession.class);result.setData(weChatSession);String unionid =weChatSession.getUnionid();//获取用户的唯一标识String openId = weChatSession.getOpenid();//System.out.println("openID:"+openId);//获取会话秘钥String sessionKey = weChatSession.getSession_key();//System.out.println("sessionKey:"+sessionKey);//调用service层校验数据result.setCode(0);//result = userService.checkOpenId(openId, sessionKey);return result;}else{result.setCode(1);result.setStatus(1);result.setMsg("校验失败");return result;}}catch(Exception e){e.printStackTrace();result.setCode(1);result.setStatus(1);result.setMsg("校验异常");return result;}}

这个方法拿完openid和unionid以及sessionkey之后怎么存数据库就是()自己的事情了。

那……如果该用户没有关注公众号,我要如何获取该用户的unionid呢。

②前台wx.getUserInfo获取加密后的字符串进行解密。(这里微信给了解密教程,点击超链接可以自己进去看,但没有java……只好自己搞一个。

/* * 解密* (non-Javadoc)* @see com.yspro.service.PubUserService#decryptionUserInfo(java.lang.String, java.lang.String, java.lang.String)*/@Overridepublic LayUIResult decryptionUserInfo(String encryptedData,String sessionKey, String iv) throws Exception{LayUIResult result = new LayUIResult();// 被加密的数据byte[] dataByte = Base64.decode(encryptedData);// 加密秘钥byte[] keyByte = Base64.decode(sessionKey);// 偏移量byte[] ivByte = Base64.decode(iv);// 如果密钥不足16位,那么就补足. 这个if 中的内容很重要int base = 16;if (keyByte.length % base != 0) {int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);byte[] temp = new byte[groups * base];Arrays.fill(temp, (byte) 0);System.arraycopy(keyByte, 0, temp, 0, keyByte.length);keyByte = temp;}// 初始化Security.addProvider(new BouncyCastleProvider());Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");parameters.init(new IvParameterSpec(ivByte));cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化byte[] resultByte = cipher.doFinal(dataByte);if (null != resultByte && resultByte.length > 0) {String result2 = new String(resultByte, "UTF-8");System.out.println(result2);//JSONArray ja = JSONArray.parseArray(result2);JSONObject jo = JSONObject.fromObject(result2);String openid = jo.getString("openId");String unionid = jo.getString("unionId");Map<String, String> unionid2 = new HashMap<>();boolean flag = false;unionid2 = userDao.checkUnionid(openid);if (unionid2.size() == 0 || unionid2 == null){//为空System.out.println("未能根据openid查找到unionid");}else{if(!(YSUtils.checkIsNullOrEmpty(unionid2.get("stf_sta_unionid")))){ //为空,插入unionidint insertId = userDao.setUnionId(openid,unionid);if(insertId != 0){flag = true;}}}}return result;}

这里用到了一个base64解密的jar包。下载地址:

链接:/s/1-OUeFfDKJQC2kYHUpR4epw;

提取码:92kl

到这里,获取小程序的openid和unionid就结束了。

2、获取公众号的openid和unionid.

【坑预警!!!!!】

获取公众号的openid和unionid需要获取一个AccessToken,这个token的有效期一次为7200s,一天最多获取200次(也有人说2000次我忘记api里写了多少了)。

所以你是把它存数据库还是存全局变量缓存随便你。

但:如果重复获取的话前一个token的有效时间就会变成五分钟。获取的时候两者会有一段时间并行有效。

accesstoken微信api:https://mp./wiki?t=resource/res_main&id=mp1421140183

①获取accesstoken的方法:

/* * 获取accesstoken* (non-Javadoc)* @see com.yspro.service.PubUserService#getAccessToken()*/public String getAccessToken()throws Exception {String accessToken = "";String url="https://api./cgi-bin/token?grant_type=client_credential&appid="+“公众号appid”+"&secret="+"公众号secret"; JSONObject jsonResult=CommonUtil.httpsRequest(url, "POST", "");//请求外网if(jsonResult!=null){accessToken=jsonResult.getString("access_token");String expires_in = jsonResult.getString("expires_in");Long timeStamp = System.currentTimeMillis();String time = String.valueOf((timeStamp/1000+7200));int insertId= pubUserDao.insertAccessToken(accessToken,time,expires_in);System.out.println("accessToken的值为:"+accessToken);} return accessToken;}//请求外网public static JSONObject httpsRequest(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.fromObject(buffer.toString()); } catch (ConnectException ce) { ce.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return jsonObject; } //拉取公众号openid,然后根据openid获取公众号unionid//获取api:https://mp./wiki?t=resource/res_main&id=mp1421140839@SuppressWarnings("unchecked")@Overridepublic LayUIResult getUserOpenIdList(String nextOpenid, String accessToken)throws Exception {LayUIResult result = new LayUIResult();//用户openid列表信息WechatUser openIdListInfo = null;synchronized(this){try { //查询是否有accessToken(我存在了数据库了,所以从数据库里查了 List<Map<String, Object>> accessTokenList = pubUserDao.queryAccessToken();accessToken = String.valueOf(accessTokenList.get(0).get("pro_act_code"));do{//微信公众号获取用户列表信息接口地址String requestUrl = null;if(StringUtils.isBlank(nextOpenid)){requestUrl = new StringBuffer().append("https://api./cgi-bin/user/get?access_token=").append(accessToken).toString();}else {requestUrl = new StringBuffer().append("https://api./cgi-bin/user/get?access_token=").append(accessToken).append("&next_openid=").append(nextOpenid).toString();}//后台请求RestTemplate restTemplate = new RestTemplate();openIdListInfo = restTemplate.getForObject(requestUrl, WechatUser.class);System.out.println("openIdListInfo的值为:"+openIdListInfo);if(openIdListInfo != null && openIdListInfo.getErrcode() == 0){//获取用户openid列表对象WechatOpenidInfo wxOpenidInfo = openIdListInfo.getData();System.out.println("wxOpenidInfo的值为:"+wxOpenidInfo);if(wxOpenidInfo != null){List<String> openids = wxOpenidInfo.getOpenid();if(openids != null && openids.size() > 0){//获取openid和unionidList<Map<String, Object>> userInfoList = new ArrayList<>();List<JSONObject> user_list = new ArrayList<>();for (String openid:openids) {JSONObject map = new JSONObject();map.put("openid", openid);map.put("lang", "zh_CN");user_list.add(map);}JSONObject jo = new JSONObject();jo.put("user_list",user_list);//根据公众号openid获取公众号unionidString requestUrl2 = null;requestUrl2 = new StringBuffer().append("https://api./cgi-bin/user/info/batchget?access_token=").append(accessToken).toString();RestTemplate restTemplate2 = new RestTemplate();//json转换成mapJSONObject strArr= restTemplate2.postForObject(requestUrl2,jo,JSONObject.class);userInfoList = (List<Map<String, Object>>) strArr.get("user_info_list");//插入数据库List<PubUser> list = new ArrayList<>();for (Map<String, Object> map1 : userInfoList) {if(String.valueOf(map1.get("subscribe")).equals("1")){PubUser pubUser = new PubUser();pubUser.setPro_pu_openid(String.valueOf(map1.get("openid")));pubUser.setPro_pu_unionid(String.valueOf(map1.get("unionid")));pubUser.setPro_pu_valid("1");list.add(pubUser);}}//插入数据库int insertId = 0;//删除数据库内容,重新插入pubUserDao.deletePubUserInfo();insertId = pubUserDao.insertPubUserInfo(list);if(insertId == 0){result.setCode(1);result.setMsg("获取用户列表失败");System.out.println("插入数据表失败"+result);return result;}} //拉取列表的最后一个用户的OPENIDnextOpenid = openIdListInfo.getNext_openid();result.setCode(0);result.setMsg("获取用户列表成功");System.out.println(result);return result;}}else {openIdListInfo.setErrcode(40000);openIdListInfo.setErrmsg("获取关注用户列表失败"); result.setData(openIdListInfo);return result;}}while (openIdListInfo.getCount() == 10000); } catch (Exception e) {//LOG.error("获取用户列表失败",e);openIdListInfo .setErrcode(40000);openIdListInfo .setErrmsg("获取用户列表失败");e.printStackTrace();result.setData(openIdListInfo);return result; }}result.setData(openIdListInfo);return result; }

--------------------------------------------------------------到这里获取就全部结束了-----------------------------------------------

消息推送这里首先要去微信公众平台模板哪儿创建模板

模板消息官方api:https://mp./advanced/tmplmsg?action=faq&token=100943608&lang=zh_CN

//这里建议用多线程来做,否则容易卡。/*** @Description * @param @param pro_ota_id* @param @param flag* @param @return * @throws* @author Momo* @date 5月8日*/@Overridepublic LayUIResult sendMessage(String pro_ota_id,String flag) throws Exception{LayUIResult result2 = new LayUIResult();List<Map<String, Object>> accessTokenList = new ArrayList<>();accessTokenList = pubUserDao.queryAccessToken();String accessToken = String.valueOf(accessTokenList.get(0).get("pro_act_code"));String tmpurl = "https://api./cgi-bin/message/template/send?access_token="+accessToken;JSONObject json = new JSONObject();List<Map<String, Object>> infoList = new ArrayList<>();//根据出差申请id获取要推送的审批人union-再根据审批人的union找到审批人的公众号openid,进行推送infoList = pushDao.getOpenId(pro_ota_id,flag);for(int i=0;i<infoList.size();i++){ //循环推送json.put("touser", infoList.get(i).get("openid"));//所要发送的用户openIdjson.put("template_id", "模板id");json.put("page", "pages/index/index");//点击模板可以跳转到小程序的具体界面//json.put("form_id", formId);//用户的fromId或者预订单IdJSONObject jo = new JSONObject();jo.put("appid","公众号appid");jo.put("pagepath", "pages/me/me");json.put("miniprogram", jo);json.put("topcolor", "#173177");json.put("data", JsonMsg(infoList.get(i)));//这个data可以直接调用上文的JsonMsg方法生成所需要发送给用户的信息String result = httpsRequest(tmpurl, "GET", json.toString()); //注意推送需要是get模式JSONObject resultJson = JSON.parseObject(result);System.out.println("模板消息返回数据:"+resultJson);String errmsg = (String) resultJson.get("errmsg");if(!"ok".equals(errmsg)){ //如果为errmsg为ok,则代表发送成功,公众号推送信息给用户了。result2.setCode(1);result2.setMsg("error");}}result2.setCode(0);result2.setMsg("success");return result2;}/*** @param map * @method packJsonmsg* @参数@param first 头部* @参数@param remark 说明* @参数@return* @返回类型:JSONObject*/public JSONObject JsonMsg(Map<String, Object> map){JSONObject json = new JSONObject();try {JSONObject jsonFirst = new JSONObject();if(String.valueOf(map.get("pro_apv_ptype")).equals("pro_apv_ptype_001")){jsonFirst.put("value", map.get("name")+"向您提交了一个"+map.get("typename")+"申请");}else{jsonFirst.put("value", map.get("name")+"向您抄送了一个"+map.get("typename")+"申请");}jsonFirst.put("color", "#173177");json.put("first", jsonFirst);/*** 信息部分JSON*/JSONObject k1 = new JSONObject();k1.put("value", map.get("typename"));k1.put("color", "#173177");json.put("keyword1", k1);JSONObject k2 = new JSONObject();k2.put("value", map.get("name"));k2.put("color", "#173177");json.put("keyword2", k2);JSONObject k3 = new JSONObject();k3.put("value", map.get("time"));k3.put("color", "#173177");json.put("keyword3", k3);JSONObject k4 = new JSONObject();k4.put("value", map.get("content"));k4.put("color", "#173177");json.put("keyword4", k4);//具体模板消息有几个参数就写几个 可查看小程序后台模板消息JSONObject jsonRemark = new JSONObject();jsonRemark.put("value", "请进入小程序进行审批");jsonRemark.put("color", "#173177");json.put("remark", jsonRemark);} catch (JSONException e) {e.printStackTrace();}return json;}/*** http请求方法* @param requestUrl* @param requestMethod* @param outputStr* @return*/public String httpsRequest(String requestUrl, String requestMethod, String outputStr){try {URL url = new URL(requestUrl);HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();conn.setDoOutput(true);conn.setDoInput(true);conn.setUseCaches(false);// 设置请求方式(GET/POST)conn.setRequestMethod(requestMethod);conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");// 当outputStr不为null时向输出流写数据if (null != outputStr) {OutputStream outputStream = conn.getOutputStream();// 注意编码格式outputStream.write(outputStr.getBytes("UTF-8"));outputStream.close();}// 从输入流读取返回内容InputStream inputStream = conn.getInputStream();InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String str = null;StringBuffer buffer = new StringBuffer();while ((str = bufferedReader.readLine()) != null) {buffer.append(str);}// 释放资源bufferedReader.close();inputStreamReader.close();inputStream.close();inputStream = null;conn.disconnect();return buffer.toString();} catch (ConnectException ce) {System.out.println("连接超时:{}");} catch (Exception e) {System.out.println("https请求异常:{}");}return null;}

-------------------------------------------------------------------------------------------------------------------------------------------

公众号推送到这里就结束了(吐魂

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。