1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 小程序关联公众号推送公众号消息

小程序关联公众号推送公众号消息

时间:2020-05-30 23:25:22

相关推荐

小程序关联公众号推送公众号消息

最近项目有个需求要把小程序和公众号关联到一起,发布商品,下单的时候的时候给用户推送消息小程序要跟微信公众号(服务号认证300块,订阅号不行)绑定到一起,要先绑定到微信开放平台(需要认证300块)绑定完成后小程序登录就可以获取unionid了,关于怎么获取unionid网上有很多教程,这里的unionid需要在微信开放平台绑定后才能看到。关联公众号,根据unionid来查询,这里我是先获取小程序的unionid然后存入数据库,再新建一个表,存放公众号的unionid和公众号的openid获取公众号的unionidopenid,微信公众号里面有个设置与开发-基本配置 -服务器配置把他开启,这个里面的token是自己自定义的需要和后端一致不然不能提交保存

@GetMapping(value = "/verify_wx_token")public String verifyWXToken(HttpServletRequest request) throws AesException {String msgSignature = request.getParameter("signature");String msgTimestamp = request.getParameter("timestamp");String msgNonce = request.getParameter("nonce");String echostr = request.getParameter("echostr");//下面这个方法里面有自定义的token 需要和服务器配置定义的一致if (WXPublicUtils.verifyUrl(msgSignature, msgTimestamp, msgNonce)) {return echostr;}return null;}

工具类

public class WXPublicUtils {/*** 验证Token* @param msgSignature 签名串,对应URL参数的signature* @param timeStamp 时间戳,对应URL参数的timestamp* @param nonce 随机串,对应URL参数的nonce** @return 是否为安全签名* @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息*/public static boolean verifyUrl(String msgSignature, String timeStamp, String nonce)throws AesException {// 这里的 WXPublicConstants.TOKEN 填写你自己设置的Token就可以了String signature = SHA1.getSHA1("你服务器配置中自定义的token", timeStamp, nonce);if (!signature.equals(msgSignature)) {throw new AesException(AesException.VALIDATE_SIGNATURE_ERROR);}return true;}

import java.security.MessageDigest;import java.util.Arrays;public class SHA1 {/*** 用SHA1算法验证Token** @param token票据* @param timestamp 时间戳* @param nonce随机字符串* @return 安全签名* @throws AesException*/public static String getSHA1(String token, String timestamp, String nonce) throws AesException {try {String[] array = new String[] {token, timestamp, nonce };StringBuffer sb = new StringBuffer();// 字符串排序Arrays.sort(array);for (int i = 0; i < 3; i++) {sb.append(array[i]);}String str = sb.toString();// SHA1签名生成MessageDigest md = MessageDigest.getInstance("SHA-1");md.update(str.getBytes());byte[] digest = md.digest();StringBuffer hexstr = new StringBuffer();String shaHex = "";for (int i = 0; i < digest.length; i++) {shaHex = Integer.toHexString(digest[i] & 0xFF);if (shaHex.length() < 2) {hexstr.append(0);}hexstr.append(shaHex);}return hexstr.toString();} catch (Exception e) {e.printStackTrace();throw new AesException(PUTE_SIGNATURE_ERROR);}}}

import com.thoughtworks.xstream.XStream;import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;import com.thoughtworks.xstream.io.xml.XppDriver;import org.dom4j.Document;import org.dom4j.DocumentException;import org.dom4j.Element;import org.dom4j.io.SAXReader;import javax.servlet.http.HttpServletRequest;import java.io.IOException;import java.io.InputStream;import java.util.HashMap;import java.util.List;import java.util.Map;public class XmlUtil {/*** xml转map*/public static Map<String, String> xmlToMap(HttpServletRequest request) throws IOException, DocumentException {HashMap<String, String> map = new HashMap<String, String>();SAXReader reader = new SAXReader();InputStream ins = request.getInputStream();Document doc = reader.read(ins);Element root = doc.getRootElement();@SuppressWarnings("unchecked")List<Element> list = (List<Element>) root.elements();for (Element e : list) {map.put(e.getName(), e.getText());}ins.close();return map;}public static WechatNotifyRequestVO fromXML(String xml, Class clazz, Class... childClazz) {XStream xmlStream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_")));XStream.setupDefaultSecurity(xmlStream);xmlStream.processAnnotations(new Class[]{clazz});xmlStream.processAnnotations(childClazz);xmlStream.allowTypes(new Class[]{clazz});xmlStream.allowTypes(childClazz);xmlStream.ignoreUnknownElements();Object result = xmlStream.fromXML(xml);return (WechatNotifyRequestVO) result;}/*** 对象组装成xml** @param object 要转换的对象* @return xml文档*/public static String toXML(Object object) {//转换成XMLXStream xmlStream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_")));XStream.setupDefaultSecurity(xmlStream);xmlStream.processAnnotations(new Class[]{object.getClass()});xmlStream.allowTypes(new Class[]{object.getClass()});return xmlStream.toXML(object);}}

import com.thoughtworks.xstream.annotations.XStreamAlias;import io.swagger.annotations.ApiModelProperty;import lombok.Data;import lombok.experimental.Accessors;/*** 详情见微信官方文档* https://developers./doc/offiaccount/Message_Management/Receiving_event_pushes.html*/@Accessors(chain = true)@XStreamAlias(value = "xml")public class WechatNotifyRequestVO {@ApiModelProperty("开发者微信号")@XStreamAlias(value = "ToUserName")private String toUserName;public String getToUserName() {return toUserName;}public void setToUserName(String toUserName) {this.toUserName = toUserName;}public String getFromUserName() {return fromUserName;}public void setFromUserName(String fromUserName) {this.fromUserName = fromUserName;}public Integer getCreateTime() {return createTime;}public void setCreateTime(Integer createTime) {this.createTime = createTime;}public String getMessageType() {return messageType;}public void setMessageType(String messageType) {this.messageType = messageType;}public String getEvent() {return event;}public void setEvent(String event) {this.event = event;}@ApiModelProperty("发送方帐号(一个OpenID)")@XStreamAlias(value = "FromUserName")private String fromUserName;@ApiModelProperty("消息创建时间 (整型)")@XStreamAlias(value = "CreateTime")private Integer createTime;@ApiModelProperty("消息类型,event")@XStreamAlias(value = "MsgType")private String messageType;@ApiModelProperty("事件类型,subscribe(订阅)、unsubscribe(取消订阅)")@XStreamAlias(value = "Event")private String event;}

配置好后,后端需要监控你的关注或取消关注的事件,我们这边关注后就能获取公众号用户这边的信息,然后去查询unionidopenid,这样就能根据小程序的unionid来查询公众号的openid,这个代码里面的访问名和公众号服务配置的名字是一样的,写在同一个controller下面,只不过一个是GET(验证服务器)一个是POST(监控公众号关注事件

private final static Logger logger = LoggerFactory.getLogger(WeixinMsgController. class);//关注或取消公众号事件@PostMapping(value = "/verify_wx_token", produces = "text/plain;charset=utf-8")public Object notify(HttpServletRequest req, HttpServletResponse resp) {try {req.setCharacterEncoding("UTF-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();}resp.setCharacterEncoding("UTF-8");String message = "success";try {//把微信返回的xml信息转义成mapMap<String, String> map = null;try {map = XmlUtil.xmlToMap(req);} catch (IOException e) {e.printStackTrace();}System.out.println("微信接收到的消息为:"+map.toString());String fromUserName = map.get("FromUserName");//消息来源用户标识 openidString toUserName = map.get("ToUserName");//消息目的用户标识 公众号idString msgType = map.get("MsgType");//消息类型(event或者text)System.out.println("用户openId:"+fromUserName);System.out.println("公众号:"+toUserName);System.out.println("消息类型为:"+msgType);String eventType = map.get("Event");//事件类型System.out.println(eventType);String unionid = getUnionid(fromUserName);if(eventType.equals("subscribe")){//关注了System.out.println(unionid);LitemallUnionid unionids=litemallUserService.findByun(unionid);if(unionids==null){//查询公众号表是否存在过这个用户,没有就新增litemallUserService.addun(fromUserName,unionid);}else{System.out.println("已存在该用户");//更新公众号表的关注状态litemallUserService.updtype1(fromUserName);}}else if(eventType.equals("unsubscribe")){//没关注 更新状态litemallUserService.updtype0(fromUserName);}} catch (DocumentException e) {e.printStackTrace();}System.out.println("关注微信公众号自动回复的消息内容为:"+message);return message;}/**这边返回出去的是 公众号的unionid**/public static String getUnionid(String openId) {String requestUrl = "https://api./cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID";String url = requestUrl.replace("OPENID", openId).replace("ACCESS_TOKEN", "你自己的公众号token");JSONObject obj = WeiXinUtil.HttpGet(url);// String nickName = (String)obj.get("nickname");String unionid = (String)obj.get("unionid");return unionid;}

这样的话我们小程序的unionid和公众号的unionid就都拿到了,然后就可以根据小程序那边登录后拿到的unionid去查询公众号表里面的openid了,之后发送推送信息,因为我这里是在小程序中订阅商家然后发布商品后发送消息给用户,所以需要循环获取openid

import com.alibaba.fastjson.JSON;import org.springframework.beans.factory.annotation.Autowired;import org.ponent;import java.io.IOException;import java.io.InputStream;import java.io.OutputStreamWriter;import .HttpURLConnection;import .URL;import java.util.HashMap;import java.util.List;import java.util.Map;@Componentpublic class WechatMsgs {@Autowiredprivate LitemallUserService userService;@Autowiredprivate LitemallGroupService litemallGroupService;public void Send(Integer userId,String name,String retailPrice,String starttime,String endtime) {// 接口地址String sendMsgApi = "https://api./cgi-bin/message/template/send?access_token="+ "你公众号的token";//跟据用户id查询订阅过的商家有几个,商家id对应用户表里面的id,//我这边是子查询所以直接把公众号的用户给查出来了, 然后循环List<LitemallUnionid> unionids=litemallGroupService.cxunionid(userId);LitemallUser user=userService.findById(userId);//循环公众号列表for(LitemallUnionid u:unionids){//openIdString toUser =""+u.getOpenid()+"";//消息模板IDString template_id = "wYhlJQXV4Zr2-lmf7gOMYXhDlWB_wilklbnSq7E2cys";//整体参数mapMap<String, Object> paramMap = new HashMap<String, Object>();Map<String, Object> xcx = new HashMap<String, Object>();//消息主题显示相关mapMap<String, Object> dataMap = new HashMap<String, Object>();//根据自己的模板定义内容和颜色dataMap.put("first",new DataEntity("您订阅的"+user.getNickname()+"社群发布了新商品","#173177"));dataMap.put("Pingou_ProductName",new DataEntity(name,"#0f0f0f"));dataMap.put("Weixin_ID",new DataEntity(user.getNickname(),"#173177"));dataMap.put("Remark",new DataEntity("点击查看详情进入主页","#F78934"));paramMap.put("touser", toUser);paramMap.put("template_id", template_id);paramMap.put("data", dataMap);// xcx.put("appid","小程序的appid"); 这个是跳转// xcx.put("pagepath","pages/index/index");// paramMap.put("miniprogram",xcx);//需要实现跳转网页的,可以添加下面一行代码实现跳转// paramMap.put("url","http://xxxxxx.html");System.out.println(doGetPost(sendMsgApi,"POST",paramMap));}}/*** 调用接口 post* @param apiPath*/public static String doGetPost(String apiPath, String type, Map<String, Object> paramMap){OutputStreamWriter out = null;InputStream is = null;String result = null;try{URL url = new URL(apiPath);// 创建连接HttpURLConnection connection = (HttpURLConnection) url.openConnection();connection.setDoOutput(true);connection.setDoInput(true);connection.setUseCaches(false);connection.setInstanceFollowRedirects(true);connection.setRequestMethod(type) ; // 设置请求方式connection.setRequestProperty("Accept", "application/json"); // 设置接收数据的格式connection.setRequestProperty("Content-Type", "application/json"); // 设置发送数据的格式connection.connect();if(type.equals("POST")){out = new OutputStreamWriter(connection.getOutputStream(), "UTF-8"); // utf-8编码out.append(JSON.toJSONString(paramMap));out.flush();out.close();}// 读取响应is = connection.getInputStream();int length = (int) connection.getContentLength();// 获取长度if (length != -1) {byte[] data = new byte[length];byte[] temp = new byte[512];int readLen = 0;int destPos = 0;while ((readLen = is.read(temp)) > 0) {System.arraycopy(temp, 0, data, destPos, readLen);destPos += readLen;}result = new String(data, "UTF-8"); // utf-8编码}} catch (IOException e) {e.printStackTrace();} finally {try {is.close();} catch (IOException e) {e.printStackTrace();}}return result;}

小程序发布商品成功后公众号收到消息

总结

小程序和公众号绑定到同一个开放平台下;如果是新的公众号没有任何用户关注的话,可以直接在后端监控关注事件然后去数据库对比;如果是已经有公众号用户了,就需要先拉取一遍公众号的用户存入数据库然后再进行比对;公众号服务器配置需要是80端口或者443端口才能提交,token也要和后端对应,否则会 提示参数错误之类的;小程序和公众号的关联都是通过unionid来联系的,这里一个用户表一个公众号表,小程序用户登录后得到unionid,然后存入数据库,公众号用户关注后获取unionid和openid,之后根据小程序的unionid去查询公众号的unionid得到openid之后就可以直接推送消息啦。

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